When working with models in Django with DateTimeField such as
updated_at, and so on, we often come across the issue of supporting different timezones, especially when your intended audience is spread out in multiple timezones.
Quite often, during the database/backend design process, you will find yourself deciding on this topic by asking questions such as: "do we save timestamps in our own current local timezone, and then translate it to the user's timezone on the frontend?"
This is where Django's i18n (shorthand for "internationalization") support for timezone comes in handy.
Django stores datetime information in UTC in the database, uses timezone-aware datetime objects internally, and translates them to the end user’s time zone in templates and forms.
Setting timezone support in settings.py
In settings.py, we can enable support for timezones by setting
USE_TZ and providing which
TIME_ZONE this Django instance should use, for instance:
# settings.py USE_TZ = True TIME_ZONE = "America/New_York"
USE_TZ is set to True and
TIME_ZONE "UTC" by default when you run
Django's time zone support uses pytz by default and a list of
TIME_ZONE values can be found by running:
import pytz print(pytz.all_timezones) # ["Africa/Abidjan", "Africa/Accra", ..., "Asia/Seoul", "UTC", ...]
"Naïve" DateTime objects
To create a
datetime object, we simply use the
from datetime import datetime start_time = datetime.now()
While this is sufficient for most cases, the
start_time object here is considered as "naïve". When you attempt to store this naive timestamp to a model instance, Django will complain about timezone support with the following message:
RuntimeWarning: DateTimeField start_time received a naive datetime (2021-01-23 12:34:56) while time zone support is active.
datetime object has a property named
tzinfo (stands for timezone information), that provides an offset for the timezone from UTC (Coordinated Universal Time). For example, US Eastern Standard Time is UTC -05:00, and US Eastern Daylight Savings Time is UTC -04:00. (Note how the UTC "zero" is absolute and thus the local time change affects the offset instead).
"Aware" DateTime objects
DateTime object simply means that it has a
Django conveniently provides timezone support via its
utils module; i.e. to convert a
DateTime object from above snippet:
from datetime import datetime from django.utils import timezone start_time = datetime.now() # naive aware_start_time = timezone.make_aware(datetime.now()) # aware