在 DST 添加时间增量后时区转换错误

Wrong timezone shift after adding a time delta over DST

我正在尝试将一个 tz 感知时间戳移动一个月。由于 datetime.timedelta 没有月份选项,因此应使用包 relativedelta

问题出现在时间点在夏令时之后,移位后的结果会在夏令时之前。

例如将 2022-04-26 07:00:00+02:00 移回一个月。预期是 2022-03-26 07:00:00+01:00 然而,结果将是 2022-03-26 07:00:00+02:00(+02:00 而不是 +01:00)

这是一个代码示例:

import pytz
import datetime
from dateutil.relativedelta import relativedelta

berlin = pytz.timezone("Europe/Berlin")
base_date = berlin.localize(datetime.datetime(2022, 4, 26, 7, 0))
offset = relativedelta(months=1, day=0, 
                       hour=base_date.hour, minute=base_date.minute, 
                       second=base_date.second, microsecond=0)
shifted = base_date - offset

expected = berlin.localize(datetime.datetime(2022, 3, 26, 7, 0))
print("shifted: ", shifted)
print("expected: ", expected)

这将打印:

shifted:  2022-03-26 07:00:00+02:00
expected:  2022-03-26 07:00:00+01:00

结果是错误的,因为那一天 2022-03-26 CET 必须总是有 +1 小时的班次。

看来您需要使用 .astimezone 才能获得所需的结果。如下所示。


import pytz
import datetime
from dateutil.relativedelta import relativedelta

berlin = pytz.timezone("Europe/Berlin")
base_date = berlin.localize(datetime.datetime(2022, 4, 26, 7, 0))
offset = relativedelta(months=1)
shifted = (base_date - offset).astimezone(berlin)
# shifted = shifted.astimezone(berlin)

expected = berlin.localize(datetime.datetime(2022, 3, 26, 7, 0))
print("base:", base_date)
print("shifted: ", shifted)
print("expected: ", expected)

我在 PyTz

的示例和用法下找到了这个

既然你用了dateutil,为什么不用它来处理tz呢?

from datetime import datetime
import dateutil

offset = dateutil.relativedelta.relativedelta(months=1)

dt = datetime(2022,4,26,7,tzinfo=dateutil.tz.gettz("Europe/Berlin"))

print(dt, dt-offset)
# 2022-04-26 07:00:00+02:00 2022-03-26 07:00:00+01:00

旁注,dateutil 语义也与 Python 3.9 way to handle time zone 一致。