Python: astimezone(None) дает осведомленность о дате и времени, не зная о летнем времени
astimezone(None)
это удобный способ локализовать объект datetime на местное время, то есть настройки вашей ОС ( документы, пример). Однако я заметил, что есть нюанс. Поскольку я нахожусь на CET/CEST, и у нас только что было изменение DST, я играл с осведомленными datetime и timedelta.1
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
t_DSTactive = datetime(2020,10,23, tzinfo=ZoneInfo('Europe/Berlin'))
t_DSTinactive = datetime(2020,10,26, tzinfo=ZoneInfo('Europe/Berlin'))
print(t_DSTinactive - t_DSTactive)
# 3 days, 0:00:00
Как и ожидалось,
timedelta
показывает разницу во времени2 на стене, которая составляет 3 дня между этими датами. Из-за перехода с активного летнего времени на неактивное летнее время продолжительность по UTC составляет 3 дня и 1 час:
t_DSTactive = t_DSTactive.astimezone(timezone.utc)
t_DSTinactive = t_DSTinactive.astimezone(timezone.utc)
print(t_DSTinactive - t_DSTactive)
# 3 days, 1:00:00
С помощью
asttimezone(None)
для локализации вроде все нормально (UTC+2 → UTC+1):
DSTinactive = datetime(2020,10,26).astimezone(None)
print(DSTactive, DSTinactive)
# 2020-10-23 00:00:00+02:00 2020-10-26 00:00:00+01:00
...но
timedelta
включает +1 час после перехода на летнее время:
print(DSTinactive - DSTactive)
# 3 days, 1:00:00
Что здесь происходит?
- 1 Я использую MS Windows 10; результат может отличаться на других платформах
- 2 см. Также: Семантика арифметики даты и времени с учетом часовых поясов
1 ответ
Глядя на
repr()
объектов datetime, полученных с помощью
.astimezone(None)
, мы видим, что
tzinfo
атрибут "только"
timedelta
в обоих случаях:
print(repr(DSTactive))
print(repr(DSTinactive))
# datetime.datetime(2020, 10, 23, 0, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200), 'Mitteleuropäische Sommerzeit'))
# datetime.datetime(2020, 10, 26, 0, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'Mitteleuropäische Zeit'))
Другими словами, фиксированное смещение UTC, а не часовой пояс в географическом смысле (включая предписанные изменения летнего времени). Фиксированное смещение, конечно, не учитывает изменения летнего времени. С учетом смещений расчет правильно дает 3 дня с разницей в 1 час.
Предыстория: в src datetime мы видим, что
astimezone(None)
звонки
_local_timezone()
чтобы получить tzinfo, который возвращает это как фиксированное смещение.
Хотя удобно,
astimezone(None)
здесь может привести к неожиданным результатам. Способ обойти эту проблему, конечно, заключается в локализации datetime в местном часовом поясе. Здесь tzlocal может оказать большую помощь, особенно в Windows, которая особенно неохотно сообщает имя часового пояса.