How to get the current user's time zone in Django?

15.2k Views Asked by At

I'm trying to get my Django app work with the current user's time zone but I'm not getting any results...

In my settings.py file I set:

TIME_ZONE = 'UTC'

And in my views.py, I set at the top of the code:

activate(settings.TIME_ZONE)

But this is not working, while creating a post, is getting my last time zone that was 'Madrid', instead of my current time zone.

Is there a way to make this work?

Thank you!

4

There are 4 best solutions below

1
On

From https://docs.djangoproject.com/en/3.1/topics/i18n/timezones/

from django.utils import timezone

now = timezone.now()
0
On

here is the source of this django timezone

Add the following middleware to MIDDLEWARE:

import pytz

from django.utils import timezone

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

    def __call__(self, request):
        tzname = request.session.get('django_timezone')
        if tzname:
            timezone.activate(pytz.timezone(tzname))
        else:
            timezone.deactivate()
        return self.get_response(request)

Create a view that can set the current timezone:

from django.shortcuts import redirect, render

def set_timezone(request):
    if request.method == 'POST':
        request.session['django_timezone'] = request.POST['timezone']
        return redirect('/')
    else:
        return render(request, 'template.html', {'timezones': pytz.common_timezones})

Include a form in template.html that will POST to this view:

{% load tz %}
{% get_current_timezone as TIME_ZONE %}
<form action="{% url 'set_timezone' %}" method="POST">
    {% csrf_token %}
    <label for="timezone">Time zone:</label>
    <select name="timezone">
        {% for tz in timezones %}
        <option value="{{ tz }}"{% if tz == TIME_ZONE %} selected{% endif %}>{{ tz }}</option>
        {% endfor %}
    </select>
    <input type="submit" value="Set">
</form>

Time zone aware input in forms¶ When you enable time zone support, Django interprets datetimes entered in forms in the current time zone and returns aware datetime objects in cleaned_data.

If the current time zone raises an exception for datetimes that don’t exist or are ambiguous because they fall in a DST transition (the timezones provided by pytz do this), such datetimes will be reported as invalid values.

Time zone aware output in templates¶ When you enable time zone support, Django converts aware datetime objects to the current time zone when they’re rendered in templates. This behaves very much like format localization.

Warning

Django doesn’t convert naive datetime objects, because they could be ambiguous, and because your code should never produce naive datetimes when time zone support is enabled. However, you can force conversion with the template filters described below.

Conversion to local time isn’t always appropriate – you may be generating output for computers rather than for humans. The following filters and tags, provided by the tz template tag library, allow you to control the time zone conversions.

Template tags¶ localtime¶ Enables or disables conversion of aware datetime objects to the current time zone in the contained block.

This tag has exactly the same effects as the USE_TZ setting as far as the template engine is concerned. It allows a more fine grained control of conversion.

To activate or deactivate conversion for a template block, use:

{% load tz %}

{% localtime on %}
    {{ value }}
{% endlocaltime %}

{% localtime off %}
    {{ value }}
{% endlocaltime %}

Note

The value of USE_TZ isn’t respected inside of a {% localtime %} block.

timezone¶ Sets or unsets the current time zone in the contained block. When the current time zone is unset, the default time zone applies.

{% load tz %}

{% timezone "Europe/Paris" %}
    Paris time: {{ value }}
{% endtimezone %}

{% timezone None %}
    Server time: {{ value }}
{% endtimezone %}

get_current_timezone¶ You can get the name of the current time zone using the get_current_timezone tag:

{% get_current_timezone as TIME_ZONE %}

Alternatively, you can activate the tz() context processor and use the TIME_ZONE context variable.

0
On

You can automatically detect and apply the user's current timezone rather than applying only one timezone set to TIME_ZONE in settings.py.

You can see my answer explaining 2 ways without and with django-tz-detect to do that.

0
On

I hope this can help someone. Since Django can't automatically detect what the user's timezone is, I had the idea of saving the user's timezone in a cookie with JS on the landing page.

Place in base.html

<script>
    // Timezone settings
    const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; // e.g. "America/New_York"
    document.cookie = "django_timezone=" + timezone;
</script>

And I followed the steps that are indicated in the official Django documentation with some slight modifications.

import zoneinfo
from django.utils import timezone

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

    def __call__(self, request):
        try:
            # get django_timezone from cookie
            tzname = request.COOKIES.get("django_timezone")
            if tzname:
                timezone.activate(zoneinfo.ZoneInfo(tzname))
            else:
                timezone.deactivate()
        except Exception as e:
            timezone.deactivate()

        return self.get_response(request)