第 23 课 · 进阶 · 19 分钟

Python datetime 日期与时间

准确处理日历日期和简单的时间间隔。

datetime日期运算timedeltaISO 日期

牛奶盒上写着「周五前用完」,可周五不是一个天数。日期有自己的算术。日历上的日期和时间上的某一刻,差在哪里?

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 运行时,可能需要几秒钟。

浏览器内 Python本地运行 · 无需账号
首次运行会从 CDN 下载 Pyodide。修改后点击“运行代码”。

练习本课

12 道题,作答后立即看到解释。

查看 12 道题答案开始练习
← pathlib 路径assert 测试 →