Python 处理日期与时间不必引入第三方框架,标准库 datetime 就覆盖了创建、格式化、解析、时间间隔运算、时区绑定和组件替换等常见需求。本文按实际编码顺序梳理 datetime 模块的核心类与常用方法,并给出可直接运行的代码片段,方便在日志时间戳、任务调度、数据清洗等脚本场景中复用。
一、模块中的核心类
datetime 是 Python 标准库模块,围绕日期与时间提供了一组类:date 表示日期,time 表示时间,datetime 表示日期加时间,timedelta 表示时间间隔,tzinfo 用于承载时区信息。日常脚本里出现频率最高的是 datetime 与 timedelta,前者是数据载体,后者是运算单位。
二、创建日期与时间对象
三个类都通过构造函数传入年、月、日、时、分、秒等字段完成实例化,注意 date 只接收年月日,time 只接收时分秒,datetime 则把两组字段合并在一起。
- from datetime import date, time, datetime
- # 创建日期
- d = date(2021, 11, 2)
- print(d)
- # 创建时间
- t = time(12, 30, 45)
- print(t)
- # 创建日期和时间
- dt = datetime(2021, 11, 2, 12, 30, 45)
- print(dt)
复制代码
这段代码的输出分别是纯日期、纯时间和完整时间戳,也是后续格式化与计算的输入基础。
三、对象与字符串之间的互转
脚本与外部系统交互时,时间几乎都以字符串形态出现,因此 strftime 与 strptime 是一对必须掌握的方法:strftime 负责把对象转成字符串,strptime 负责把字符串还原成对象。
- from datetime import datetime
- dt = datetime(2021, 11, 2, 12, 30, 45)
- formatted_dt = dt.strftime('%Y-%m-%d %H:%M:%S')
- print(formatted_dt)
复制代码
反向解析时,格式串必须与输入字符串严格对应,否则会抛出解析异常:
- from datetime import datetime
- date_string = '2021-11-02 12:30:45'
- dt = datetime.strptime(date_string, '%Y-%m-%d %H:%M:%S')
- print(dt)
复制代码
这里的 %Y 表示四位年份,%m 表示两位月份,%d 表示两位日期,%H、%M、%S 分别对应时、分、秒。格式串与实际字符串一旦错位(例如用 %m 去匹配月份位置却写成了 %d),解析就会失败,这是时间处理脚本最常见的报错来源之一。
四、用 timedelta 做时间加减
timedelta 表示一段时间长度,可与 datetime 对象直接相加或相减,得到新的时间点。它支持 days、hours 等关键字参数,适合计算“N 天后”“N 小时前”这类偏移量。
- from datetime import datetime, timedelta
- dt = datetime(2021, 11, 2, 12, 30, 45)
- # 加上5天
- dt_plus_5_days = dt + timedelta(days=5)
- print(dt_plus_5_days)
- # 减去3小时
- dt_minus_3_hours = dt - timedelta(hours=3)
- print(dt_minus_3_hours)
复制代码
注意运算结果是一个新对象,原对象保持不变,这种不可变特性让时间计算在函数间传递时更安全。
五、时区信息的处理
datetime 自身通过 tzinfo 参数承载时区,具体时区对象可以借助第三方库 pytz 获取。使用前需要先安装 pytz,再通过 timezone 名称取得时区实例,最后作为 tzinfo 传入构造函数。
- from datetime import datetime
- import pytz
- # 创建时区对象
- tz = pytz.timezone('Asia/Shanghai')
- # 创建时区时间
- dt = datetime(2021, 11, 2, 12, 30, 45, tzinfo=tz)
- print(dt)
复制代码
这段示例演示的是“带时区的时间对象”,打印结果会附带时区标识。脚本中凡是涉及跨地区时间展示、日志对齐,都建议从创建阶段就显式带上时区信息,避免后续再做二次推断。
六、读取与替换时间组件
datetime 对象的每个字段都有对应属性,可以直接读取,用于分组统计、按小时聚合等场景。
- from datetime import datetime
- dt = datetime(2021, 11, 2, 12, 30, 45)
- print(dt.year)
- print(dt.month)
- print(dt.day)
- print(dt.hour)
- print(dt.minute)
- print(dt.second)
复制代码
如果只想改动其中某几个字段,用 replace 更直观,它返回修改后的新对象,未指定的字段保持原值:
- from datetime import datetime
- dt = datetime(2021, 11, 2, 12, 30, 45)
- dt_replaced = dt.replace(year=2022, month=12, day=31)
- print(dt_replaced)
复制代码
处理“把某天的时间归零”“统一改成月初”这类需求时,replace(day=1, hour=0, minute=0, second=0) 之类的写法比手工重构造更简洁。
七、比较与算术运算
datetime 对象之间支持比较,也支持通过差值得到 timedelta 再参与后续运算,下面的示例先用两个时间点做大小比较,再把时间差放大两倍后加到起点上。
- from datetime import datetime, timedelta
- dt1 = datetime(2021, 11, 2, 12, 30, 45)
- dt2 = datetime(2021, 11, 5, 15, 20, 10)
- # 比较运算
- print(dt1 < dt2)
- # 算术运算
- dt3 = dt1 + (dt2 - dt1) * 2
- print(dt3)
复制代码
dt2 - dt1 得到的是一个 timedelta,乘以 2 仍然是 timedelta,再与 dt1 相加得到新的时间点。这种“差值—缩放—回加”的组合在排期推算、区间外推等逻辑里很实用。
八、实践中的注意点
第一,格式串是解析成败的关键,strptime 的格式必须与字符串逐字符对应,出现 ValueError 时优先检查分隔符与占位符是否一致。第二,涉及时区时建议尽早绑定 tzinfo,不要在字符串里手工拼接时区偏移。第三,时间加减统一走 timedelta,避免自行用秒数换算,以免在跨天、跨月时写错边界。第四,pytz 属于额外依赖,部署脚本时要把安装步骤写进依赖清单。
以上内容覆盖了 datetime 模块在日期创建、格式化、字符串解析、时间间隔运算、时区绑定、组件读取与替换以及比较运算方面的基本用法,掌握这些方法后,绝大多数脚本级时间处理需求都可以在标准库范围内完成。 |