pytz时区转换因冬令时变更触发AmbiguousTimeError,求原因及解决方法
解决冬令时切换导致的pytz时区转换崩溃问题
问题背景
使用pytz进行日期时区转换时,因凌晨3点的冬令时切换触发AmbiguousTimeError崩溃,核心疑问:
- 为何冬令时变更会导致时区转换崩溃?
- 如何修复该bug?
出错代码
purchase_date = make_aware( datetime.strptime( sale.findtext('n:purchasedate', namespaces={'n': ns}), '%d/%m/%Y-%H:%M' ), timezone('Europe/Paris') )
错误回溯
Traceback (most recent call last): File "/app/manage.py", line 15, in <module> execute_from_command_line(sys.argv) File "/usr/local/lib/python3.11/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line utility.execute() File "/usr/local/lib/python3.11/site-packages/django/core/management/__init__.py", line 436, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/usr/local/lib/python3.11/site-packages/django/core/management/base.py", line 412, in run_from_argv self.execute(*args, **cmd_options) File "/usr/local/lib/python3.11/site-packages/django/core/management/base.py", line 458, in execute output = self.handle(*args, **options) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ purchase_date = make_aware( ^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/utils/timezone.py", line 287, in make_aware return timezone.localize(value, is_dst=is_dst) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/pytz/tzinfo.py", line 366, in localize raise AmbiguousTimeError(dt) pytz.exceptions.AmbiguousTimeError: 2023-10-29 02:08:00
说明:代码执行时间为凌晨3:02,冬令时切换发生在凌晨3:00。
问题解答
一、为何冬令时变更会导致崩溃?
欧洲巴黎的冬令时切换是在每年10月最后一个周日的凌晨3点,时钟会回拨1小时到凌晨2点。这就导致2023-10-29 02:08:00这个时间点会出现两次:一次是切换前的夏令时UTC+2,一次是切换后的冬令时UTC+1。
当你用make_aware(底层调用pytz的localize)转换这个时间时,pytz无法确定你指的是哪一个时区偏移的时间,因此抛出AmbiguousTimeError,避免产生歧义的时间戳。
二、如何修复该bug?
修复的核心是明确告诉pytz这个模糊时间对应的时区偏移,有两种常用方案:
方案1:指定is_dst参数明确时区状态
在调用make_aware时传入is_dst参数,直接指定该时间属于夏令时还是冬令时:
purchase_date = make_aware( datetime.strptime( sale.findtext('n:purchasedate', namespaces={'n': ns}), '%d/%m/%Y-%H:%M' ), timezone('Europe/Paris'), # 根据业务场景选择:True表示夏令时,False表示冬令时 is_dst=False )
- 如果业务中这个时间是切换后的冬令时,传
is_dst=False;如果是切换前的夏令时,传is_dst=True。
方案2:改用zoneinfo(Python 3.9+内置)替代pytz
Python 3.9及以上版本内置了zoneinfo模块,处理模糊时间时会默认采用统一规则(通常是取较晚的那个时区偏移,即冬令时),无需手动指定:
from zoneinfo import ZoneInfo from django.utils.timezone import make_aware purchase_date = make_aware( datetime.strptime( sale.findtext('n:purchasedate', namespaces={'n': ns}), '%d/%m/%Y-%H:%M' ), ZoneInfo('Europe/Paris') )
注意:如果使用Windows系统,需要额外安装tzdata包来获取时区数据:pip install tzdata
内容的提问来源于stack exchange,提问作者Lirit
相关产品推荐
相关产品推荐

