牛奶盒上写着「周五前用完」,可周五不是一个天数。日期有自己的算术。日历上的日期和时间上的某一刻,差在哪里?
datetime 模块把日历日期、时钟时间和时间间隔分开。初学阶段先掌握 date 和 timedelta。只有当数据确实表示不同地区共同观察的某一瞬间时,才需要引入时区。 你还会区分日期与时刻、解析 ISO 文本,并避免把一个月当成 30 天。
创建一个日期
date(year, month, day) 会校验参数,并返回不可变的日期对象。isoformat() 生成可排序的 YYYY-MM-DD 形式。需要拆分年月日时,可以直接访问 year、month 和 day。
from datetime import date
start = date(2026, 1, 15)
print(start.isoformat())
print(start.year, start.month, start.day)一个日历日期
加上 timedelta
timedelta 表示一段时长。把它加到日期上会返回新日期,原对象不变。两个日期相减会得到一个 timedelta,可以用 days 属性读取天数。
from datetime import date, timedelta
start = date(2026, 1, 30)
end = start + timedelta(days=3)
print(end.isoformat())
print((end - start).days)时长与日期差
格式化成读者能看懂的形式
strftime 按格式模式生成字符串。数字日期用 %Y、%m 和 %d。月份名和星期名依赖区域设置,输出必须到处一致时优先使用数字格式。
from datetime import date
day = date(2026, 10, 27)
print(day.strftime("%Y/%m/%d"))
print(day.isoformat())稳定的数字格式
日期不是时刻
date 只保存日历上的一天,没有时区。datetime 保存时钟读数;只有带时区的 datetime 才能表示不同地区共同观察的某一瞬间。不要把无时区 datetime 和带时区 datetime 相减;先判断数据到底是日期还是时刻。
from datetime import date, datetime, timezone
day = date(2026, 10, 28)
moment = datetime(2026, 10, 28, 12, 0, tzinfo=timezone.utc)
print(day.isoformat())
print(moment.isoformat())
print(moment.tzinfo is not None)日历日与带时区的时刻
先解析 ISO 文本,再做运算
fromisoformat 接受 YYYY-MM-DD 形状,拒绝含糊的日/月顺序。不要从 28/10/2026 这样的字符串猜顺序;向数据源确认格式并显式解析。在边界捕获 ValueError,并报告坏值。
from datetime import date
for raw in ["2026-10-28", "28/10/2026"]:
try:
parsed = date.fromisoformat(raw)
print(parsed.year, parsed.month, parsed.day)
except ValueError:
print("not ISO:", raw)先校验形状,再使用日期
一个月不是 30 天
timedelta 计算的是固定天数,不是日历月。1 月 31 日加 30 天会落到 3 月,而不是 2 月 28 日。如果规则是“一个日历月”,要用显式的月份计算或维护良好的日期库,不要写成 30 天。
from datetime import date, timedelta
start = date(2026, 1, 31)
print((start + timedelta(days=30)).isoformat())
print((start + timedelta(days=59)).isoformat())固定天数与日历月
本课要点
- date(y, m, d) 创建一个经过校验的日历日期。
- timedelta(days=n) 表示一段时长。
- 日期加 timedelta 会返回新的日期对象。
- 输出不能依赖区域设置时,用数字形式的 strftime 模式。
- 运算前先选 date 或带时区的 datetime;timedelta 表示固定时长。
常见错误
- 在存储日期时使用含糊的日/月顺序。
- 试图原地修改日期;date 对象不可变。
- 还没分清日期和时刻,就急着添加时区。
- 把无时区和带时区的 datetime 相减,还期待有意义的结果。
创建 date(2026, 12, 31),加一天,并用 ISO 格式打印两个日期。
动手试试
改改变量、先预测输出,再运行代码。第一次点击“运行代码”时会下载 Python 运行时,可能需要几秒钟。
练习本课
12 道题,作答后立即看到解释。