python - `timedelta` object not accounting for daylight savings
问题描述
I am trying to get the appropriate time range to query in a database (where datetimes are stored in UTC) in the local timezone of a user. Here's some odd behavior that I'm finding that I don't know how to work around:
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
The Daylight savings change is lost somehow when normalizing the end
variable contstructed by adding a timedelta
object to start
. Why could this be happening?
解决方案
Not sure about the expected behavior on the datetime calculations, but I'll just explain the behavior from shared code samples.
pytz.localize
creates a timezone aware datetime instance. When NY timezone is used to localize
the naive datetime, it assigns the correct timezone, EDT
until November 3rd, and EST
for Nevember 4th and later. Let's exclude timedelta
here:
>>> 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>)
As seen, the DstTzInfo
are different, as one would expect, because NY DST ends on November 3rd.
The shared code sample creates start
by localizing
November 3rd, which assigns EDT
as tzinfo
to the datetime object (using DST). To create end
, timedelta
of 1 day is added to start
, but the tzinfo
of the datetime
object is kept 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>
So end
is datetime
for November 4th, but DstTzInfo
info is still the same as November 3rd. And this is different than localizing
a naive datetime
of November 4th, which doesn't use DST.
推荐阅读
- python - 在树莓派中使用中断检查继电器的状态
- python - Python:检查数字中的条件以在列表中以 130* 开头
- javascript - 在 Angular 6 中使用地理编码 API
- spring - 如何从服务器上的帖子接收不止一个正文数据
- python - AttributeError:“NoneType”对象没有属性“字符串”
- c# - 如何使用编码读取丢弃的 unicode 文本 C#
- android - Volley 发送参数和 JSON 正文
- pycharm - 打开git项目时无法解析pycharm中的引用
- c++ - C++ 将键映射到对象
- jquery - 全选功能在jquery中无法正常工作