Как вы конвертируете наивное datetime в DST-осведомленное datetime в Python? - PullRequest
13 голосов
/ 03 ноября 2011

В настоящее время я работаю над серверной частью системы календаря, которая возвращает наивные даты Python.Интерфейс работает так, как пользователь создает различные события календаря, а внешний интерфейс возвращает наивную версию созданного ими события (например, если пользователь выбирает 5 октября 2020 года с 15:00 до 16:00, интерфейс возвращаетdatetime.datetime (2020, 10, 5, 15, 0, 0) в качестве начала и datetime.datetime (2011, 10, 5, 16, 0, 0) в качестве конца.

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

Внешний интерфейс находится вне моего контроля, поэтому я не могу изменить данныечто я получаю. Дизайн базы данных также находится вне моего контроля, поэтому я не могу изменить, какие данные хранятся и как.

Вот примерный подход, который я использовал до сих пор:

import pytz
def convert_to_UTC(naive_datetime, user_tz_preference):
    user_datetime = naive_datetime.replace(tzinfo=user_tz_preference)
    utc_datetime = user_datetime.astimezone(pytz.utc)

Проблема, с которой я столкнулся, связана с переходом на летнее время:

>>> from datetime import datetime
>>> import pytz
>>> user_tz_preference = pytz.timezone('US/Pacific')
>>> naive_datetime = datetime(2011, 10, 26, 12, 0, 0)
>>> user_datetime = naive_datetime.replace(tzinfo=user_tz_preference)
>>> user_datetime
datetime.datetime(2011, 10, 26, 12, 0, tzinfo=<DstTzInfo 'US/Pacific' PST-1 day, 16:00:00 STD>)
>>> received_utc = user_datetime.astimezone(pytz.utc)
>>> received_utc
datetime.datetime(2011, 10, 26, 20, 0, tzinfo=<UTC>)
>>> expected_utc = datetime(2011, 10, 26, 19, 0, tzinfo=pytz.utc)
>>> expected_utc == received_utc
False

Обратите внимание, что используется замена.устанавливает часовой пояс PST вместо PDT независимо от даты, что дает смещение UTC на 8 часов вместо ожидаемого смещения DST на 7 часов, поэтому время в конечном итоге сохраняется неправильно.

Какие варианты у меня есть для преобразования наивной даты и времени в правильную tzinfo PDT (или другую летнюю дату, относящуюся к часовому поясу)?

(Кроме того, обратите внимание, что не все пользователи живут в часовом поясе, который наблюдает летнее время, или могут жить в часовом поясе, который переключается в разное время, поэтому для выполнения такого решения, как коррекция временной задержки перед сохранением,Мне нужно знать, поддерживает ли часовой пояс летнее время и в какие даты он переключается).

1 Ответ

19 голосов
/ 03 ноября 2011

Pytz's localize функция может сделать это: http://pytz.sourceforge.net/#localized-times-and-date-arithmetic

from datetime import datetime
import pytz    

tz = pytz.timezone('US/Pacific')
naive_dt = datetime(2020, 10, 5, 15, 0, 0) 
utc_dt = tz.localize(naive_dt, is_dst=None).astimezone(pytz.utc)
# -> 2020-10-05 22:00:00+00:00
...