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 = ...), к сожалению, назван. Это функция, которая является случайной по своему поведению. Я бы посоветовал не использовать эту функцию для установки часовых поясов, если вам не нравятся боли, вызванные самим собой. Я уже достаточно пострадал от использования этой функции.