Skip to content

Python Django: How to Set the Timezone in Django

How to configure Django's timezone settings, work with timezone-aware datetime objects, and implement user-specific timezones using TIME_ZONE, USE_TZ, and middleware.

Handling timezones correctly is critical for any Django application that serves users across different regions or needs to store and display accurate timestamps. Misconfigured timezone settings can lead to confusing discrepancies in event schedules, log entries, and user-facing dates.

This guide walks you through configuring the default timezone, working with timezone-aware datetime objects, and supporting user-specific timezones in Django.

Setting the Default Timezone in Django Settings

Configuring TIME_ZONE

The most fundamental step is setting the TIME_ZONE variable in your settings.py file. This defines the default timezone your Django application uses for display and form input interpretation.


TIME_ZONE = 'America/New_York'

Django uses the IANA time zone database for timezone names. Some commonly used values include:

Timezone Name Region
UTC Coordinated Universal Time
America/New_York Eastern Time (US)
Europe/London Greenwich Mean Time / BST
Asia/Tokyo Japan Standard Time
Asia/Kolkata India Standard Time

Enabling Timezone Support with USE_TZ

To ensure Django handles timezone conversions properly, set USE_TZ to True in your settings.py:


USE_TZ = True

When USE_TZ = True, Django:

  • Stores all DateTimeField values in UTC in the database.
  • Converts datetime values to the timezone specified in TIME_ZONE when rendering templates or forms.
  • Makes timezone.now() return a timezone-aware datetime object in UTC.

Working with Timezone-Aware Datetime Objects

Getting the Current Time

Django's timezone module provides utility functions for creating and manipulating timezone-aware datetime objects:

from django.utils import timezone

now = timezone.now()
print(now)

Converting to a Different Timezone

You can convert a UTC datetime to any other timezone using astimezone():

from django.utils import timezone
import zoneinfo

now = timezone.now()

eastern = zoneinfo.ZoneInfo('America/New_York')
now_eastern = now.astimezone(eastern)
print(now_eastern)

tokyo = zoneinfo.ZoneInfo('Asia/Tokyo')
now_tokyo = now.astimezone(tokyo)
print(now_tokyo)

Common Mistake: Using Naive Datetime Objects

A frequent error is using Python's datetime.now() instead of Django's timezone.now(), which creates a naive datetime without timezone information:

from datetime import datetime

naive_now = datetime.now()
print(naive_now)

When you try to save a naive datetime to a DateTimeField with USE_TZ = True, Django raises a warning:

RuntimeWarning: DateTimeField received a naive datetime while time zone support is active.

The correct approach:

from django.utils import timezone

aware_now = timezone.now()
print(aware_now)

Using localtime in Models

When displaying datetime fields to users, use Django's localtime function to convert stored UTC values to the active timezone:

from django.db import models
from django.utils.timezone import localtime


class Event(models.Model):
    name = models.CharField(max_length=200)
    start_time = models.DateTimeField()

    def get_local_start_time(self):
        """Return start_time converted to the currently active timezone."""
        return localtime(self.start_time)

    def __str__(self):
        return f"{self.name} at {self.get_local_start_time()}"

The localtime() function converts the datetime to whichever timezone is currently active: either the default TIME_ZONE from settings or a timezone activated via timezone.activate().

Handling User-Specific Timezones

For applications with a global user base, you may want each user to see dates and times in their own timezone.

Step 1: Add a Timezone Field to the User Profile

Create a profile model that stores each user's timezone preference:

import zoneinfo
from django.db import models
from django.conf import settings

TIMEZONE_CHOICES = [
    (tz, tz) for tz in sorted(zoneinfo.available_timezones())
]


class UserProfile(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='profile'
    )
    timezone = models.CharField(
        max_length=63,
        choices=TIMEZONE_CHOICES,
        default='UTC'
    )

    def __str__(self):
        return f"{self.user.username} ({self.timezone})"

Step 2: Activate the User's Timezone with Middleware

Rather than manually activating the timezone in every view, use a middleware to do it automatically for each request:


import zoneinfo
from django.utils import timezone


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

    def __call__(self, request):
        if request.user.is_authenticated:
            try:
                user_tz = request.user.profile.timezone
                timezone.activate(zoneinfo.ZoneInfo(user_tz))
            except Exception:
                timezone.deactivate()
        else:
            timezone.deactivate()

        response = self.get_response(request)
        return response

Register the middleware in settings.py:


MIDDLEWARE = [
    'yourapp.middleware.UserTimezoneMiddleware',
]

With this middleware in place, all template rendering and localtime() calls will automatically use the logged-in user's timezone.

Step 3: Display Localized Times in Templates

Django templates automatically convert datetime values to the active timezone when USE_TZ = True. You can also use the {% timezone %} template tag for explicit control:

{% load tz %}

<!-- Uses the currently active timezone (set by middleware) -->
<p>Event starts at: {{ event.start_time }}</p>

<!-- Explicitly render in a specific timezone -->
{% timezone "Asia/Tokyo" %}
    <p>Event starts at (Tokyo): {{ event.start_time }}</p>
{% endtimezone %}

Automatically Detecting the User's Timezone

Instead of asking users to manually select a timezone, you can detect it automatically using JavaScript and send it to the server.

Client-Side Detection

<form method="post" action="/update-timezone/">
    {% csrf_token %}
    <input type="hidden" id="timezone-input" name="timezone" value="">
    <button type="submit" id="tz-submit" style="display:none;">Submit</button>
</form>

<script>
    document.addEventListener('DOMContentLoaded', function() {
        var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
        document.getElementById('timezone-input').value = tz;
        // Optionally auto-submit or store in a cookie/session
    });
</script>

Server-Side View

from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required


@login_required
def update_timezone(request):
    if request.method == 'POST':
        user_timezone = request.POST.get('timezone', 'UTC')
        profile = request.user.profile
        profile.timezone = user_timezone
        profile.save()
    return redirect('home')

Summary

Setting / Function Purpose
TIME_ZONE in settings.py Sets the project's default timezone
USE_TZ = True Enables timezone-aware storage and conversion
timezone.now() Returns the current UTC time as a timezone-aware object
localtime(dt) Converts a datetime to the currently active timezone
timezone.activate(tz) Sets the active timezone for the current thread/request
zoneinfo.ZoneInfo('...') Creates a timezone object from an IANA timezone name

By configuring your default timezone, enabling USE_TZ, and implementing user-specific timezone support through middleware, your Django application will handle time-related data accurately regardless of where your users are located.

Navigation