2

I have this code that behaves in a rather strange way and opens the question, how should I deal with timezones? So, first I have a datetime object I build from the info a user posts:

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)

This prints event.date_start.hour:6, event.date_start.tzinfo:Etc/GMT+2 and is_aware:True. Then, inmediatlty after saving the object and printing the hour, it redirects to the event_detail view, very simple:

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)
    ...

And it prints event.date_start.hour:8 and event.date_start.tzinfo:UTC. (it has replaced the tz info with UTC) I don't understand why. I am saving the object with a clear tz_info. Plz note that I printed the hour after I saved the object and then after I retrieved it in the other view. It has a difference of two hours that must have something to do with the timezone the user selected (GMT + 2). Why is this? Which is the best way to save this data?

The user submits "6:00 AM" + "GMT+2" in the form and then later when I want to show the time in the event detail html ({{ event.date_start|date:"h:i A" }}) it displays "8:00 AM".

Alejandro Veintimilla
  • 10,743
  • 23
  • 91
  • 180

2 Answers2

4

I assume you're using PostgreSQL to save the timezone aware timestamp.

It's important to understand that (contrary to the name and popular belief) PostgreSQL doesn't save the timezone of the timezone aware timestamp. It's just a way to tell PostgreSQL that the value is not in some local time, but is timezone aware.

PostgreSQL then converts it to UTC and stores as such. If the original timezone is important, you need to store it separately.

More info on the topic: https://www.postgresqltutorial.com/postgresql-timestamp/

The best way to store this data is a separate column (usually called timezone). I use https://pypi.org/project/django-timezone-field/

Then either activate timezone (https://docs.djangoproject.com/en/3.1/ref/utils/#django.utils.timezone.activate) or use localtime (https://docs.djangoproject.com/en/3.1/ref/utils/#django.utils.timezone.localtime) util function.

Krzysztof Szularz
  • 5,151
  • 24
  • 35
0

As per the Django docs,

"When support for time zones is enabled, Django stores DateTime information in UTC in the database. It’s still good practice to store data in UTC in your database. The main reason is the Daylight Saving Time (DST). "

So saving DateTime in UTC format in the database as expected.

Now, going ahead with your requirement. In order to display the time back in the timezone which was used for saving you need to add a column in the DB to store the timezone info.

While retrieving the DateTime, convert it into the required timezone back using the tzinfo stored in DB.

This is the correct way of doing. Hope this helps you understand better.

Vinay
  • 577
  • 6
  • 17