问题

pytz 是 Python 的时区库,可用于补充标准库 datetime 对时区支持的不足。例如:

import pytz
from pytz import timezone

shanghai = timezone('Asia/Shanghai')
amsterdam = timezone('Europe/Amsterdam')
utc = pytz.UTC

若将这些时区对象直接作为 tzinfo 传入 datetime 构造函数,会出现时间偏移:

from datetime import datetime

d = datetime(2019, 1, 1, 12, 0, 0, tzinfo=shanghai)
print(d)

输出通常与预期相差几分钟(不同地区偏移量不同)。

原因

pytz 文档指出,大多数时区对象与 datetime 构造函数的 tzinfo 参数不兼容,除非该时区没有夏令时(如 UTC)。

It is safe for timezones without daylight saving transitions though, such as UTC.

正确用法

localize

对于「原生」datetime(不含时区),应使用时区对象的 localize 方法:

from datetime import datetime
from pytz import timezone

t = datetime(2019, 1, 1, 12, 0, 0)
amsterdam = timezone('Europe/Amsterdam')
ams_dt = amsterdam.localize(t)
print(ams_dt)
# 2019-01-01 12:00:00+01:00

astimezone

对于已带时区的 datetime,可使用 astimezone 转换至其他时区:

shanghai = timezone('Asia/Shanghai')
sh_dt = ams_dt.astimezone(shanghai)
print(sh_dt)
# 2019-01-01 19:00:00+08:00

结论

构造 Asia/Shanghai 等时区的时间对象时,推荐:

  • 先创建原生 datetime,再调用 localize
  • 或先创建 UTC 时间,再使用 astimezone 转换。

参考链接