Datetime с часовым поясом pytz. Различное смещение в зависимости от того, как устанавливается tzinfo

Сегодня я столкнулся с интересной ситуацией. Может ли кто-нибудь объяснить, почему смещения для ts1 и ts2 различны? ts1 - это объект datetime, который точно зависит от часовой стрелки. ts2 - объект datetime, начинающийся с наименования по времени и заменяющий tzinfo. Однако они заканчиваются разными смещениями.

>>> from pytz import timezone
>>> EST = timezone('America/New_York')
>>> ts1 = datetime.datetime.now(tz=EST)
>>> ts2 = datetime.datetime.now()
>>> ts2 = ts2.replace(tzinfo=EST)
>>> print ts1
2014-05-16 11:25:16.749748-04:00
>>> print ts2
2014-05-16 11:25:19.581710-05:00

Ответ 1

Когда вы вызываете ts2.replace(tzinfo=EST), объект tzinfo, который вы получаете, не совпадает с тем, который вы получаете с помощью ts1:

>>> ts1
datetime.datetime(2014, 5, 16, 11, 51, 7, 916090, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
>>> ts2
datetime.datetime(2014, 5, 16, 11, 51, 30, 922692, tzinfo=<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>)

В итоге вы получите LMT вместо EDT.

Документация pytz фактически отмечает, что использование pytz с аргументом tzinfo стандартных объектов datetime просто не работает для многих часовых поясов:

К сожалению, использование аргумента tzinfo стандартного времени datetime конструкторы '' не работают '' с pytz для многих часовых поясов.

>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=amsterdam).strftime(fmt) '2002-10-27 12:00:00 LMT+0020'

Это безопасно для часовых поясов без перехода на летнее время, хотя, таких как UTC:

>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=pytz.utc).strftime(fmt) '2002-10-27 12:00:00 UTC+0000'

Я не совсем уверен, почему первый работает; возможно, потому, что на самом деле нет необходимости конвертировать что-либо, когда объект изначально сконструирован с объектом tzinfo.

Edit

Ah, документация Python отмечает, что использование datetime.datetime.now() с аргументом tz эквивалентно:

EST.fromutc(datetime.utcnow().replace(tzinfo=EST))

Это означает, что вы конвертируете с UTC, что безопасно с pytz. Итак, почему первый работает.

Ответ 2

Согласно документации, правильный способ применения часового пояса к наивному datetime - с помощью метода localize.

ts1 = eastern.localize(datetime.datetime.now())

Кроме того, я рекомендую использовать имя EST в качестве имени переменной, поскольку оно обычно является стандартным для "Восточного стандартного времени", а America/New_York содержит как "Восточное стандартное время" (EST), так и "Восточное дневное время" ( EDT).