datetime.now() 不带时区是错误的,必须用 datetime.now(timezone.utc) 或 datetime.now(zoneinfo("asia/shanghai"));timezone.utc 是常量不可调用;zoneinfo 比 pytz 更可靠;存数据库应优先存 utc 时间。

datetime.now() 不带 timezone 就是错的
Python 的 datetime.now() 默认返回「本地时间但无时区信息」,也就是 tzinfo=None。这种对象在跨时区、存数据库、和 API 交互时会出问题——比如你在北京生成的时间,传到服务器(UTC)后可能被当成 UTC 时间直接解析,结果差 8 小时。
正确做法是:只要涉及时间比较、序列化、持久化,就必须用带 tzinfo 的 datetime。
- 别写
datetime.now(),改用datetime.now(timezone.utc)(获取 UTC 时间)或datetime.now(ZoneInfo("Asia/Shanghai"))(需 Python 3.9+) - 旧项目还在用
pytz?注意pytz.timezone("Asia/Shanghai").localize(dt)才安全,直接dt.replace(tzinfo=...)会出错 - 如果读的是用户输入或字符串(如
"2024-05-20 14:30"),先用datetime.fromisoformat()或strptime()解析,再显式加上时区,别依赖系统本地时区
timezone.utc 是常量,不是函数
timezone.utc 是 datetime.timezone 类的一个实例,不是可调用对象。写成 timezone.utc() 会报 TypeError: 'datetime.timezone' object is not callable——这是新手高频错误。
它只适用于需要 UTC 时间的场景,比如记录日志、生成 token 过期时间、和外部服务对齐时间基准。
立即学习“Python免费学习笔记(深入)”;
- ✅ 正确:
datetime.now(timezone.utc)、datetime(2024, 1, 1, tzinfo=timezone.utc) - ❌ 错误:
timezone.utc()、datetime.now().replace(tzinfo=timezone.utc)(后者虽不报错,但若原 datetime 是本地时间,replace 会忽略夏令时偏移,逻辑错误) - 注意:
timezone.utc和timezone(timedelta(hours=0))等价,但前者更语义清晰、性能略好
ZoneInfo("Asia/Shanghai") 比 pytz 更可靠
Python 3.9 引入的 zoneinfo 模块,底层用 IANA 时区数据库,能正确处理历史夏令时变更、政区调整等细节;而 pytz 在 localize() 以外的用法(比如直接 astimezone())容易返回错误偏移。
如果你的环境支持 Python 3.9+,没理由继续用 pytz。
- 安装:标准库,无需 pip(但旧系统可能需要
pip install backports.zoneinfo) - 使用:
from zoneinfo import ZoneInfo,然后datetime.now(ZoneInfo("Asia/Shanghai")) - ⚠️ 注意:
"Asia/Shanghai"不能写成"CST"或"GMT+8"——这些缩写不唯一、不可靠,IANA 数据库不认 - 查可用时区:
ZoneInfo.available_timezones()(返回 set,很大,建议按需过滤)
time.sleep() 和 timezone 没关系,但 time.time() 有
time.sleep() 只管挂起线程,和时区完全无关;但 time.time() 返回的是 Unix timestamp(自 1970-01-01 UTC 起的秒数),本质是 UTC 标量。很多人误以为它是“本地时间戳”,导致用它算“今天零点”时出错。
真正需要时区感知的时间计算,应该用 datetime + ZoneInfo,而不是对 time.time() 做加减。
- ❌ 错误:用
time.time() + 3600 * 8算“北京时间一小时后”,忽略了夏令时、闰秒、系统时区配置异常 - ✅ 正确:用
datetime.now(ZoneInfo("Asia/Shanghai")) + timedelta(hours=1) - 存数据库时,优先存 UTC timestamp(
datetime.now(timezone.utc)),读取时再转本地显示——避免时区转换污染业务逻辑
事情说清了就结束。最麻烦的不是写对代码,而是让整个系统里所有时间操作都统一时区策略,尤其当 legacy 代码混着 pytz、datetime.utcnow()、time.localtime() 一起用的时候。










