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

#django #django-models #django-timezone

#django #django-модели #django-часовой пояс

Вопрос:

У меня есть этот код, который ведет себя довольно странно и открывает вопрос, как мне следует обращаться с часовыми поясами? Итак, сначала у меня есть объект 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 утра».

Комментарии:

1. Обязательно ознакомьтесь с документацией о часовых поясах Django.

2. @KevinChristopherHenry прочитал это. Отредактировал вопрос, запустил щедрость.

Ответ №1:

Я предполагаю, что вы используете 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.

Ответ №2:

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

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

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

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

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

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