`timedelta` 对象不考虑夏令时

`timedelta` object not accounting for daylight savings

我正在尝试获取适当的时间范围以在用户本地时区的数据库中查询(其中日期时间以 UTC 格式存储)。这是我发现的一些我不知道如何解决的奇怪行为:

import pytz
from datetime import datetime, timedelta

local_tz = pytz.timezone("America/New_York")
utc = pytz.timezone("UTC")

start = local_tz.localize(datetime(2019, 11, 3))  # 2019-11-03 00:00:00-04:00
end = start + timedelta(days=1)  # 2019-11-04 00:00:00-04:00

start_utc = utc.normalize(start)  # 2019-11-03 04:00:00+00:00
end_utc = utc.normalize(end)  # 2019-11-04 04:00:00+00:00

utc.normalize(local_tz.localize(datetime(2019, 11, 4)))  # 2019-11-04 05:00:00+00:00

通过将 timedelta 对象添加到 start 来规范化 end 变量时,夏令时更改会以某种方式丢失。为什么会这样?

不确定日期时间计算的预期行为,但我将仅解释共享代码示例中的行为。

pytz.localize 创建一个时区感知日期时间实例。当纽约时区用于 localize 原始日期时间时,它会分配正确的时区,EDT 直到 11 月 3 日,EST 为 11 月 4 日及以后。让我们在这里排除 timedelta

>>> import pytz
>>> from datetime import datetime, timedelta
>>> tz_ny = pytz.timezone("America/New_York")
>>> tz_ny.localize(datetime(2019, 11, 3))
datetime.datetime(2019, 11, 3, 0, 0, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
>>> tz_ny.localize(datetime(2019, 11, 4))
datetime.datetime(2019, 11, 4, 0, 0, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)

正如所见,DstTzInfo 与预期不同,因为纽约夏令时在 11 月 3 日结束。

共享代码示例在 localizing 11 月 3 日之前创建了 start,它将 EDT 作为 tzinfo 分配给日期时间对象(使用夏令时)。要创建end,1天的timedelta被添加到start,但是datetime对象的tzinfokept untouched:

>>> start = tz_ny.localize(datetime(2019, 11, 3))
>>> start.tzinfo
<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>
>>> end = start + timedelta(days=1)
>>> end.tzinfo
<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>

因此 end 是 11 月 4 日的 datetime,但 DstTzInfo 信息仍与 11 月 3 日相同。这不同于 localizing 11 月 4 日的天真 datetime,它不使用夏令时。