Джанго. Как правильно сохранять время и часовые пояса

У меня есть этот код, который ведет себя довольно странно и открывает вопрос, как мне быть с часовыми поясами? Итак, сначала у меня есть объект datetime, который я создаю из информации, которую публикует пользователь:

time_zone = request.POST.get("time_zone")
date_start = request.POST.get("date_start")
time_day = request.POST.get("time_day")

time_zone_obj = pytz.timezone("Etc/" + time_zone)  # GMT + 2 in this example
date_start = datetime.strptime(date_start, "%d/%m/%Y")
date_start = date_start.replace(tzinfo=time_zone_obj)
time_day = datetime.strptime(time_day, "%I:%M %p")
date_start = date_start.replace(hour=time_day.hour, minute=time_day.minute)

...
event.date_start = date_start
event.save()
print("event.date_start.hour:%s" % event.date_start.hour)
print("event.date_start.tzinfo:%s" % event.date_start.tzinfo)
print("is_aware(event.date_start:%s)" % is_aware(event.date_start))

return redirect("event_detail", event_id=event.id)

Это печатает event.date_start.hour:6, event.date_start.tzinfo:Etc/GMT+2 и is_aware:True. Затем, сразу после сохранения объекта и печати часа, он перенаправляется на представление event_detail, очень просто:

def event_detail(request, event_id):
    event = get_object_or_404(Event, id=event_id)
    print("event.date_start.hour:%s" % event.date_start.hour)
    print("event.date_start.tzinfo:%s" % event.date_start.tzinfo)
    ...

И он печатает event.date_start.hour:8 и event.date_start.tzinfo:UTC. (он заменил информацию tz на UTC) Я не понимаю, почему. Я сохраняю объект с ясным tz_info. Пожалуйста, обратите внимание, что я напечатал час после того, как сохранил объект, а затем после того, как я получил его в другом представлении. Разница составляет два часа, что должно быть связано с выбранным пользователем часовым поясом (GMT + 2). Почему это? Как лучше сохранить эти данные?

Пользователь отправляет 6:00 + GMT+2 в форму, а затем позже, когда я хочу показать время в подробностях события html ({{ event.date_start|date:"h:i A" }}), он отображает 8:00.


person Alejandro Veintimilla    schedule 07.11.2020    source источник


Ответы (2)


Я предполагаю, что вы используете PostgreSQL для сохранения отметки времени с учетом часового пояса.

Важно понимать, что (вопреки названию и распространенному мнению) PostgreSQL не сохраняет часовой пояс временной метки с учетом часового пояса. Это просто способ сообщить PostgreSQL, что значение указано не в каком-то местном времени, а в часовом поясе.

Затем PostgreSQL преобразует его в формат UTC и сохраняет как таковой. Если исходный часовой пояс важен, его нужно хранить отдельно.

Дополнительная информация по теме: https://www.postgresqltutorial.com/postgresql-timestamp/

Лучший способ хранить эти данные — отдельный столбец (обычно называемый timezone). Я использую https://pypi.org/project/django-timezone-field/

Затем либо часовой пояс activate (https://docs.djangoproject.com/en/3.1/ref/utils/#django.utils.timezone.activate) или используйте localtime (https://docs.djangoproject.com/en/3.1/ref/utils/#django.utils.timezone.localtime) util функция.

person Krzysztof Szularz    schedule 10.11.2020

Согласно документам Django,

Когда поддержка часовых поясов включена, Django сохраняет информацию о дате и времени в формате UTC в базе данных. По-прежнему рекомендуется хранить данные в формате UTC в вашей базе данных. Основная причина — переход на летнее время (DST).

Таким образом, сохранение DateTime в формате UTC в базе данных, как и ожидалось.

Теперь, продолжая с вашим требованием. Чтобы отобразить время назад в часовом поясе, который использовался для сохранения, вам необходимо добавить столбец в БД для хранения информации о часовом поясе.

При получении DateTime преобразуйте его в требуемый часовой пояс обратно, используя tzinfo, хранящуюся в БД.

Это правильный способ сделать. Надеюсь, это поможет вам лучше понять.

person Vinay    schedule 16.11.2020