目录

pytz中的时间偏移问题

问题

pytz 是 Python 的一个时区库,可以方便的定义时区,弥补了 Python 自带 datetime 库的不足。例如:

1
2
3
4
5
6
import pytz
from pytz import timezone

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

但是如果将这些时区对象作为 tzinfo 传入 datetime 的构造函数中,则会发生时间的偏移。

1
2
3
4
5
from datetime import datetime

d = datetime(2019, 1, 1, 12, 0, 0, tzinfo=shanghai)
print(d)
# 2019-01-01 12:00:00+08:06

可以看到,与正常的结果相比,差了 6 分钟。不只是东八区有这个问题,其他的时区或多或少都有差值。

pytz

pytz 库文档中表示,上述使用方式是错误的。

tzinfo

datetime 构造函数中的tzinfo 参数与大多数的 pytz 时区不兼容,即会发生时间漂移。唯一的例外是没有夏令时转换的 UTC 时区,是安全的。

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

在 pytz 中正确处理时区的方式有两种:

localize

使用时区对象的 localize 方法,将一个 native 时间(不带时区)转换为带时区的时间。

1
2
3
4
5
6
7
8
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 方法,将一个带时区的时间,转换为另一个时区的时间。

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

解决

通过 pytz 库的文档,我们可以得出,如果想要构建一个 Asia/Shanghai 的本地时间,可以:

  • 创建 Asia/Shanghai 的 native 时间,然后通过 localize 方法转换为本地时间;
  • 使用 tzinfo=UTC 创建一个 UTC 时间,然后通过 astimezone 转换为本地时间。

参考链接