Python datetime单向时区转换异常原因及解决方法
问题描述
尝试将带时区信息的datetime.datetime对象转换为UTC时区并转为无时区的naive对象,使用代码如下:
from datetime import datetime import pytz dt: datetime = datetime(2023, 1, 2, 12, 0, 0, tzinfo=pytz.timezone("Europe/Amsterdam")) print(pytz.timezone("Europe/Amsterdam").utcoffset(dt=datetime.now())) print(dt) print(dt.astimezone(pytz.timezone("UTC")))
输出结果:
1:00:00 2023-01-02 12:00:00+00:18 2023-01-02 11:42:00+00:00
时间偏移量显示为18分钟而非预期的1小时,但反向转换(UTC转欧洲/阿姆斯特丹时区)正常:
from datetime import datetime import pytz dt: datetime = datetime(2023, 1, 2, 12, 0, 0, tzinfo=pytz.timezone("UTC")) print(dt) print(dt.astimezone(pytz.timezone("Europe/Amsterdam")))
输出:
1:00:00 2023-01-02 12:00:00+00:00 2023-01-02 13:00:00+01:00
问题原因
直接给datetime构造函数的tzinfo参数传入pytz.timezone对象会出错,因为pytz的时区对象包含历史时区数据,欧洲/阿姆斯特丹时区早期确实存在+00:18的偏移值。而datetime构造函数不会自动匹配当前时间点对应的正确时区偏移,只会使用该时区的初始历史偏移,导致结果异常。
反向转换时使用astimezone方法,pytz会根据目标时间点自动计算正确的时区偏移,因此结果符合预期。
修复方法
不要直接在datetime构造时传入tzinfo,改用pytz时区对象的localize方法绑定时区,该方法会自动匹配对应时间点的正确偏移:
from datetime import datetime import pytz amsterdam_tz = pytz.timezone("Europe/Amsterdam") # 使用localize绑定正确时区 dt = amsterdam_tz.localize(datetime(2023, 1, 2, 12, 0, 0)) print(amsterdam_tz.utcoffset(dt)) print(dt) print(dt.astimezone(pytz.UTC))
输出符合预期:
1:00:00 2023-01-02 12:00:00+01:00 2023-01-02 11:00:00+00:00
更简便的转换方式
如果要转成UTC的naive对象,可以在转到UTC后,用replace(tzinfo=None)去掉时区信息:
# 接上面的修复代码 utc_naive_dt = dt.astimezone(pytz.UTC).replace(tzinfo=None) print(utc_naive_dt) # 输出:2023-01-02 11:00:00
另外,推荐使用Python 3.9+自带的zoneinfo模块(无需额外安装pytz),用法更直观:
from datetime import datetime from zoneinfo import ZoneInfo # 直接构造带正确时区的datetime dt = datetime(2023, 1, 2, 12, 0, 0, tzinfo=ZoneInfo("Europe/Amsterdam")) # 转UTC并转为naive对象 utc_naive_dt = dt.astimezone(ZoneInfo("UTC")).replace(tzinfo=None) print(dt) # 2023-01-02 12:00:00+01:00 print(utc_naive_dt) # 2023-01-02 11:00:00
内容的提问来源于stack exchange,提问作者Axel Köhler
相关产品推荐
相关产品推荐

