Pytz localize vs datetime replace
У меня возникают некоторые странные проблемы с функцией pytz.localize(). Иногда он не вносил корректировки в локализованное datetime:
.localize поведение:
>>> tz
<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD>
>>> d
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421)
>>> tz.localize(d)
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421,
tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>)
>>> tz.normalize(tz.localize(d))
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421,
tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>)
Как вы можете видеть, время не было изменено в результате операций локализации/нормализации.
Однако, если используется .replace:
>>> d.replace(tzinfo=tz)
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421,
tzinfo=<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD>)
>>> tz.normalize(d.replace(tzinfo=tz))
datetime.datetime(2009, 9, 2, 15, 1, 42, 91421,
tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>)
Который, похоже, вносит корректировки в дату и время.
Вопрос - это правильно и почему другие неправильные?
Ответы
Ответ 1
localize
просто предполагает, что наивное datetime, которое вы передаете, является "правильным" (за исключением незнания о часовом поясе!), и поэтому просто устанавливает часовой пояс, никаких других настроек.
Вы можете (и это желательно...) работать внутри UTC (а не с наивными datetimes) и использовать replace
, когда вам нужно выполнять ввод/вывод данных по локализованному пути (normalize
будет обрабатывать DST и т.п.).
Ответ 2
Я понимаю, что немного опаздываю на это...
но вот что я нашел, чтобы работать хорошо.
Работа в UTC, как сказал Алекс:
tz = pytz.timezone('Africa/Abidjan')
now = datetime.datetime.utcnow()
Затем для локализации:
tzoffset = tz.utcoffset(now)
mynow = now+tzoffset
И этот метод отлично справляется с DST
Ответ 3
Этот класс DstTzInfo используется для часовых поясов, где смещение от UTC изменяется в определенные моменты времени. Например, как вы, вероятно, знаете, во многих местах переход к "летнему времени" в начале лета, а затем к "стандартному времени" в конце лета. Каждый экземпляр DstTzInfo представляет только один из этих часовых поясов, но методы "локализовать" и "нормализовать" помогают получить правильный экземпляр.
Для Абиджана был только один переход (согласно pytz), и это было в 1912 году:
>>> tz = pytz.timezone('Africa/Abidjan')
>>> tz._utc_transition_times
[datetime.datetime(1, 1, 1, 0, 0), datetime.datetime(1912, 1, 1, 0, 16, 8)]
Объект tz, который мы выберем из pytz, представляет собой временной интервал до 1912 года:
>>> tz
<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD>
Теперь, глядя на ваши два примера, см., что когда вы вызываете tz.localize(d), вы НЕ получаете этот часовой пояс до 1912 года, добавленный к вашему наивному объекту datetime. Он предполагает, что объект datetime, который вы ему представляете, представляет собой локальное время в правильном часовом поясе для этого локального времени, которое является часовым поясом после 1912 года.
Однако в вашем втором примере, использующем d.replace(tzinfo = tz), он принимает ваш объект datetime для представления времени в часовом поясе до 1912 года. Вероятно, это не то, что вы имели в виду. Затем, когда вы вызываете dt.normalize, он преобразует это в часовой пояс, который является правильным для этого значения datetime, то есть часовой пояс после 1912 года.
Ответ 4
localize
- это правильная функция, используемая для создания объектов, поддерживающих дату и время, с исходным фиксированным значением datetime. Результирующий объект, поддерживающий дату и время, будет иметь исходное значение datetime. На мой взгляд, очень распространенный шаблон использования и тот, который, возможно, pytz может лучше документировать.
replace(tzinfo = ...)
, к сожалению, назван. Это функция, которая является случайной по своему поведению. Я бы посоветовал не использовать эту функцию для установки часовых поясов, если вам не нравятся боли, вызванные самим собой. Я уже достаточно пострадал от использования этой функции.