Django Timezones Setting Session Timezones


Python's datetime.datetime objects have a tzinfo attribute that is used to store time zone information. When the attribute is set the object is considered Aware, when the attribute is not set it is considered a Naive.

To ensure that a timezone is naive or aware, you can use .is_naive() and .is_aware()

If you have USE_TZ enabled in your file, a datetime will have time zone information attached to it as long as your default TIME_ZONE is set in

While this default time zone may be good in some cases it is likely not enough especially if you are handling users in multiple time zones. In order to accomplish this, middleware must be used.

import pytz

from django.utils import timezone

# make sure you add `TimezoneMiddleware` appropriately in
class TimezoneMiddleware(object):
    Middleware to properly handle the users timezone

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # make sure they are authenticated so we know we have their tz info.
        if request.user.is_authenticated():
            # we are getting the users timezone that in this case is stored in 
            # a user's profile
            tz_str = request.user.profile.timezone
        # otherwise deactivate and the default time zone will be used anyway

        response = self.get_response(request)
        return response

There are a few new things going on. To learn more about middleware and what it does check out that part of the documentation. In __call__ we are handling the setting of the timezone data. At first we make sure the user is authenticated, to make sure that we have timezone data for this user. Once we know we do, we active the timezone for the users session using timezone.activate(). In order to convert the time zone string we have to something usable by datetime, we use pytz.timezone(str).

Now, when datetime objects are accessed in templates they will automatically be converted from the 'UTC' format of the database to whatever time zone the user is in. Just access the datetime object and its timezone will be set assuming the previous middleware is set up properly.

{{ my_datetime_value }}

If you desire a fine grained control of whether the user's timezone is used take a look at the following:

{% load tz %}
{% localtime on %}
    {# this time will be respect the users time zone #}
    {{ your_date_time }}
{% endlocaltime %}

{% localtime off %}
    {# this will not respect the users time zone #}
    {{ your_date_time }}
{% endlocaltime %}

Note, this method described only works in Django 1.10 and on. To support django from prior to 1.10 look into MiddlewareMixin