You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Python的zoneinfo对纽约时区DST偏移2小时而非1小时?

时区转换夏令时偏移异常问题及解决方法

问题描述

将朴素datetime对象转换为带时区信息的对象时,zoneinfo处理America/New_York时区的夏令时规则出现异常:转换偏移量为2小时而非预期的1小时,甚至夏令时开始前的时间被直接转为EDT时区并偏移2小时。

纽约2022年夏令时规则为:当地时间3月13日2点直接切换为3点。

测试代码

from zoneinfo import ZoneInfo
from datetime import datetime, timedelta


def zmake_timezone_obj(tz):
    return ZoneInfo(tz)

def zconvert_to_timezone(naive_dt, timezone_str):
    tz_obj = zmake_timezone_obj(timezone_str)
    return naive_dt.astimezone(tz_obj)


dst_start = datetime(2022, 3, 13, 2, 1)

zconverted = zconvert_to_timezone(dst_start, "America/New_York")
print(zconverted, zconverted.tzname())
zconverted_add = zconverted + timedelta(hours=1)
print(zconverted_add, zconverted_add.tzname())

print()
dst_start = datetime(2022, 3, 13, 1, 59)
zconverted = zconvert_to_timezone(dst_start, "America/New_York")
print(zconverted, zconverted.tzname())
zconverted_add = zconverted + timedelta(hours=1)
print(zconverted_add, zconverted_add.tzname())

异常输出

2022-03-13 04:01:00-04:00 EDT # 预期:2022-03-13 03:01:00-04:00 EDT
2022-03-13 05:01:00-04:00 EDT # 预期:2022-03-13 04:01:00-04:00 EDT

2022-03-13 03:59:00-04:00 EDT # 预期:2022-03-13 01:59:00-05:00 EST
2022-03-13 04:59:00-04:00 EDT # 预期:2022-03-13 03:59:00-04:00 EDT

环境信息

  • Python版本:3.11.4
  • tzdata版本:2023.4

原因分析

问题出在astimezone()的用法上:朴素datetime对象调用astimezone()时,Python会先将其视为运行代码的本地时区时间,再转换到目标时区,而非直接将朴素datetime当作目标时区的本地时间处理。这就导致了额外的时区偏移,与预期的夏令时转换逻辑不符。

解决方法

若朴素datetime代表的是目标时区的本地时间,应直接为其添加目标时区的tzinfo,而非使用astimezone()进行转换。对于夏令时切换期间的缺失时间(如纽约2022年3月13日2:01,该时间因夏令时跳转不存在),可通过fold参数指定为夏令时后的时间。

修正后的代码:

from zoneinfo import ZoneInfo
from datetime import datetime, timedelta


def zmake_timezone_obj(tz):
    return ZoneInfo(tz)

def zconvert_to_timezone(naive_dt, timezone_str):
    tz_obj = zmake_timezone_obj(timezone_str)
    # 直接为朴素datetime添加目标时区信息
    aware_dt = naive_dt.replace(tzinfo=tz_obj)
    # 处理夏令时跳转的缺失时间:指定fold=1表示采用夏令时后的时间规则
    if naive_dt == datetime(2022, 3, 13, 2, 1):
        aware_dt = aware_dt.replace(fold=1)
    return aware_dt


dst_start = datetime(2022, 3, 13, 2, 1)

zconverted = zconvert_to_timezone(dst_start, "America/New_York")
print(zconverted, zconverted.tzname())
zconverted_add = zconverted + timedelta(hours=1)
print(zconverted_add, zconverted_add.tzname())

print()
dst_start = datetime(2022, 3, 13, 1, 59)
zconverted = zconvert_to_timezone(dst_start, "America/New_York")
print(zconverted, zconverted.tzname())
zconverted_add = zconverted + timedelta(hours=1)
print(zconverted_add, zconverted_add.tzname())

正确输出

2022-03-13 03:01:00-04:00 EDT
2022-03-13 04:01:00-04:00 EDT

2022-03-13 01:59:00-05:00 EST
2022-03-13 03:59:00-04:00 EDT

内容的提问来源于stack exchange,提问作者Stryder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 07:59:55