用 Python 标准库掌握时间处理:datetime 全面攻略
系列 03 – 日期/时间运算、时区、格式转换一次搞定
时间不只是“字符串”。日期会跨日、月份会变、夏令时会插入,且不同地区的基准也不同。 因此在处理日期/时间时,必须区分可显示的字符串与可计算的时间值,并养成包含时区的习惯。

本文围绕 datetime 模块,整理以下内容。
- 创建当前时间与日期
- 计算时间差(
timedelta) - 字符串格式化/解析(
strftime、strptime) - 时区处理(
timezone、zoneinfo) - 常见注意点与稳定模式
1. datetime 提供了哪些功能?
datetime 包含看似相似但职责不同的类型。
date:仅需要年-月-日time:仅需要时:分:秒datetime:日期+时间(最常用)timedelta:时间“差值”(持续时间)timezone:固定偏移时区(如 UTC+9,偏移不变)
Python 3.9+ 之后,标准库加入 zoneinfo,使得处理地区时区(如 Asia/Tokyo)更为简便。
2. 如何获取“现在”:从 naive 到 aware 的整理
2.1 naive / aware 是什么?
datetime 对象大致分为两类。
- naive datetime:没有时区信息
- aware datetime:包含时区信息(
tzinfo)
混用两者进行运算/比较会导致错误,甚至在无错误的情况下得到意外结果。
2.2 推荐的默认值:以 UTC aware 开始
统一使用 UTC 作为存储/计算基准往往更为整洁。
from datetime import datetime, timezone
utc_now = datetime.now(timezone.utc) # aware (UTC)
print(utc_now)
需要本地时间时,在显示阶段进行转换。
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
utc_now = datetime.now(timezone.utc)
tokyo_now = utc_now.astimezone(ZoneInfo("Asia/Tokyo"))
print(utc_now)
print(tokyo_now)
3. 日期/时间计算:timedelta 为核心
3.1 加减
from datetime import datetime, timedelta, timezone
now = datetime.now(timezone.utc)
print(now + timedelta(days=3))
print(now - timedelta(hours=2))
3.2 两个时间点的差值
from datetime import datetime, timezone
a = datetime(2026, 1, 1, tzinfo=timezone.utc)
b = datetime(2026, 1, 10, tzinfo=timezone.utc)
delta = b - a
print(delta.days) # 9
print(delta.total_seconds()) # 777600.0
3.3 用 timedelta 表示“期间”的感知
timedelta 以天/秒/微秒为单位。
“一个月后”这类因月长变化的表达,timedelta(days=30) 只能粗略近似;若需基于日历的“下个月同日”,则需要 dateutil 等外部工具。
4. 格式化与解析:strftime / strptime
4.1 datetime → 字符串(strftime)
from datetime import datetime, timezone
dt = datetime(2026, 1, 30, 14, 5, 0, tzinfo=timezone.utc)
print(dt.strftime("%Y-%m-%d %H:%M:%S %z"))
常用格式模式:
%Y-%m-%d: 2026-01-30%H:%M:%S: 14:05:00%z: +0000(UTC 偏移)
4.2 字符串 → datetime(strptime)
from datetime import datetime
s = "2026-01-30 14:05:00"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S")
print(dt)
此处得到的 dt 为 naive。若想明确时区,需要附加 tzinfo。
from datetime import datetime, timezone
s = "2026-01-30 14:05:00"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc)
print(dt)
replace(tzinfo=...)只是给时间点贴上时区标签,并不做时区转换。 若需转换,请使用astimezone()(见下节)。
5. 时区:区分 timezone 与 zoneinfo 的使用
5.1 固定偏移时区使用 timezone
示例:UTC、UTC+9 等偏移固定的时区。
from datetime import datetime, timezone, timedelta
kst_fixed = timezone(timedelta(hours=9))
dt = datetime(2026, 1, 30, 12, 0, tzinfo=kst_fixed)
print(dt)
5.2 地区时区使用 zoneinfo
夏令时等偏移变化的地区适合使用 zoneinfo。
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
utc_now = datetime.now(timezone.utc)
ny_now = utc_now.astimezone(ZoneInfo("America/New_York"))
print(ny_now)
5.3 replace(tzinfo=...) 与 astimezone(...) 的区别
replace(tzinfo=...):时间值不变,仅给时区贴标签astimezone(...):同一时刻在不同时区的时间表示
了解这点可大幅减少时区相关错误。
6. 常见注意点汇总
6.1 naive/aware 混用
- 内部计算时间建议使用 aware(UTC),更稳健。
- 外部输入时,立即确定时区并统一。
6.2 “本地时间”受环境影响
datetime.now() 取决于执行环境的本地设置。容器/服务器可能是 UTC,也可能不是。
使用 datetime.now(timezone.utc) 更可靠。
6.3 字符串解析的格式不匹配
strptime 对格式极为严格。若输入格式多样,需先做预处理或逐步尝试多种格式(最好限制输入格式)。
7. 三大常用模式
7.1 以 ISO 8601 存储
标准字符串表示可用 isoformat()。
from datetime import datetime, timezone
dt = datetime.now(timezone.utc)
print(dt.isoformat()) # 例如: 2026-01-30T05:12:34.567890+00:00
7.2 用“今天日期”生成文件名
from datetime import datetime
stamp = datetime.now().strftime("%Y%m%d")
filename = f"report_{stamp}.json"
print(filename)
7.3 计算到某个时间点的剩余时间
from datetime import datetime, timezone
target = datetime(2026, 2, 1, 0, 0, tzinfo=timezone.utc)
now = datetime.now(timezone.utc)
remaining = target - now
print(remaining)
print(remaining.total_seconds())
8. 结语
datetime 不仅能生成日期字符串,更能把时间变成可运算的值。结合时区(timezone、zoneinfo),即使运行环境不同,也能写出稳定的代码。
下一篇将单独讨论 random,涵盖随机数生成/采样/洗牌/种子以及安全随机数(secrets)等。
相关文章:
查看前置系列
目前没有评论。