从pytz迁移至zoneinfo:夏令时转换等效方法问询
从pytz迁移到zoneinfo时处理夏令时转换的正确方式
问题背景
从pytz切换到zoneinfo过程中,遇到夏令时转换场景下的时间计算差异:
- pytz通过
localize给原生datetime添加时区后,直接加timedelta得到的是逻辑本地时间,需调用astimezone修正为实际存在的时间 - zoneinfo用
replace添加时区后,加timedelta虽已更新时区偏移,但显示的本地时间不符合实际,调用astimezone也无法修正
核心差异
pytz的DstTzInfo对象会保留固定时区偏移,直接加timedelta不会自动调整偏移,因此需要astimezone重新计算实际时间;而zoneinfo的ZoneInfo是动态时区对象,会自动跟踪偏移变化,但直接对本地时间加timedelta会忽略夏令时回拨导致的时间重复问题,生成不存在的时间。
解决方案
最通用的正确做法是先将时区感知时间转为UTC,添加timedelta后再转回目标时区,基于绝对时间(UTC)计算可避免夏令时转换的歧义:
import datetime from zoneinfo import ZoneInfo # Python<3.9 用 backports.zoneinfo.ZoneInfo local_timezone = ZoneInfo('Europe/Copenhagen') start = datetime.datetime(2021, 10, 30, 23, 0) # 给原生datetime添加zoneinfo时区(等效pytz的localize) start_cet = start.replace(tzinfo=local_timezone) # 中转UTC计算时间,再转回目标时区 end_utc = start_cet.astimezone(datetime.timezone.utc) + datetime.timedelta(hours=5) end = end_utc.astimezone(local_timezone) print(end) # 输出:datetime.datetime(2021, 10, 31, 3, 0, tzinfo=ZoneInfo(key='Europe/Copenhagen')) print(end.utcoffset()) # 输出:datetime.timedelta(seconds=3600) # 对应CET标准时区
直接加timedelta失效的原因
欧洲哥本哈根时区在2021年10月31日凌晨2:00 CEST会回拨到1:00 CET,本地时间的2:00-3:00会重复一次。直接对start_cet加5小时得到的2021-10-31 04:00是逻辑累加结果,但实际对应的UTC时间与start_cet加5小时的绝对UTC时间不符。通过UTC中转可确保时间计算基于绝对时间,规避夏令时转换的歧义。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

