2017-02-07 9 views
3

Я пытаюсь изменить DateTime на основе часового пояса на сохранение и на нагрузку следующим образом:Сохранение локального DateTime смещение времени на 4-й минуте

входной DateTime, наряду с входной временной зоны направляются сервер и сервер должны обновить дату-время, чтобы отразить часовой пояс. Поэтому, когда он сохраняется в базе данных (PostregSQL), время UTC сохраняется (после смещения, вызванного часовым поясом, конечно).

Чтобы отразить это здесь более простой пример, который не может таким же образом:

Некоторые импорт:

>>> import datetime 
>>> import pytz 
>>> from apps.myapp.models import Project 

Создание двух входов:

>>> input_date = timezone.now() 
>>> input_date 
datetime.datetime(2017, 2, 7, 16, 7, 14, 377429, tzinfo=<UTC>) 
>>> current_tz = pytz.timezone('America/New_York') 
>>> current_tz 
<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD> 

Как вы можете видеть, часовой пояс не 5h (24 - 19 = 5), но 4h56. На этом этапе я думаю, что все в порядке, это может быть связано с летним временем.

Теперь я заменить часовой пояс на дату ввода:

>>> input_date = input_date.replace(tzinfo=current_tz) 
>>> input_date 
datetime.datetime(2017, 2, 7, 16, 7, 14, 377429, tzinfo=<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>) 

Как и следовало ожидать, время не изменилось, но часовой пояс имеет, что это хорошо.

Я поручу это значение для проекта (launch_date является DateTimeField без какого-либо конкретного варианта):

>>> project = Project.objects.get(pk=1) 
>>> project.launch_date 
datetime.datetime(2017, 1, 14, 8, 53, 57, 241718, tzinfo=<UTC>) 
>>> project.launch_date = input_date 
>>> project.launch_date 
datetime.datetime(2017, 2, 7, 16, 7, 14, 377429, tzinfo=<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>) 

Теперь я сохраню это в (и обновить с) базы данных, в результате чего Джанго/PostgreSQL делать математику:

>>> project.save() 
>>> project.refresh_from_db() 
>>> project.launch_date 
datetime.datetime(2017, 2, 7, 21, 3, 14, 377429, tzinfo=<UTC>) 

Как и ожидалось, дата теперь 4h56 впереди предыдущей даты. Я пытаюсь вернуться по местному времени:

>>> project.launch_date.astimezone(current_tz) 
datetime.datetime(2017, 2, 7, 16, 3, 14, 377429, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>) 
>>> input_date 
datetime.datetime(2017, 2, 7, 16, 7, 14, 377429, tzinfo=<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>) 

На этот раз смещение отлично 5 часов. И я пропустил 4 минуты.

3 вопросы здесь:

  • Где это 4 минуты приходит?
  • Почему astimezone не используется в течение 4 минут?
  • Как datetime может быть преобразовано в UTC, сохранено, загружено и преобразовано обратно в локальное?
+2

Возможная дубликат [поле зоны времени в isoformat] (http://stackoverflow.com/questions/26264897/time-zone-field-in-isoformat) – Uriel

+2

@UrielEli также http://stackoverflow.com/ вопросы/11473721/weird-timezone-issue-with-pytz –

ответ

1

pytz часовые пояса немного странные, как вы можете видеть по нескольким вопросам о StackOverflow. Они часто не будут показывать правильное значение смещения или названия часового пояса, если им не разрешено настраивать себя на datetime, с которыми они сопряжены. Вот что должен the documentation:

Эта библиотека поддерживает только два способа построения локализованного времени. Первый заключается в использовании метода localize(), предоставляемого библиотекой pytz.Это используется для локализации наивного DateTime (DateTime без информации временной зоны):

Второго способом построения локализованного времени является путем преобразования существующего локализованную времени с использованием стандартного astimezone() метод:

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

Это не говорит об этом прямо, но с использованием replace имеет такую ​​же проблему, как с помощью datetime конструктора.

Чтобы сделать то, что ваш код делает без 4-минутного несовпадения, вы можете использовать localize():

>>> input_date 
datetime.datetime(2017, 2, 7, 16, 7, 14, 377429, tzinfo=<UTC>) 
>>> current_tz.localize(input_date.replace(tzinfo=None)) 
datetime.datetime(2017, 2, 7, 16, 7, 14, 377429, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>) 

Я подозреваю, что это ошибка, хотя, и вы действительно хотите, чтобы выполнить преобразование часового пояса от UTC:

>>> input_date.astimezone(current_tz) 
datetime.datetime(2017, 2, 7, 11, 7, 14, 377429, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>) 
+0

Именно это я и сделал, спасибо за разъяснение. – nobe4