Python Django: How to Set the Timezone in Django
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.
# settings.py
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:
# settings.py
USE_TZ = True
When USE_TZ = True, Django:
- Stores all
DateTimeFieldvalues in UTC in the database. - Converts datetime values to the timezone specified in
TIME_ZONEwhen rendering templates or forms. - Makes
timezone.now()return a timezone-aware datetime object in UTC.
If USE_TZ is set to False, Django stores naive (timezone-unaware) datetime objects. This can cause serious bugs in applications that serve users in multiple timezones. Always keep USE_TZ = True unless you have a very specific reason not to.
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
# Returns the current time as a timezone-aware datetime in UTC
now = timezone.now()
print(now)
# Example output: 2025-07-23 14:30:00+00:00
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()
# Convert to Eastern Time
eastern = zoneinfo.ZoneInfo('America/New_York')
now_eastern = now.astimezone(eastern)
print(now_eastern)
# Example output: 2025-07-23 10:30:00-04:00
# Convert to Tokyo time
tokyo = zoneinfo.ZoneInfo('Asia/Tokyo')
now_tokyo = now.astimezone(tokyo)
print(now_tokyo)
# Example output: 2025-07-23 23:30:00+09:00
Starting with Python 3.9 and Django 4.0+, the recommended approach is to use zoneinfo.ZoneInfo from the standard library instead of pytz. If you are on an older version of Python, you can install the backports.zoneinfo package or continue using pytz.
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
# WRONG: creates a naive datetime (no timezone info)
naive_now = datetime.now()
print(naive_now)
# Output: 2025-07-23 10:30:00 (no +00:00 offset)
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
# CORRECT: creates a timezone-aware datetime in UTC
aware_now = timezone.now()
print(aware_now)
# Output: 2025-07-23 14:30:00+00:00
Never use datetime.datetime.now() or datetime.datetime.utcnow() in a Django project with USE_TZ = True. Always use django.utils.timezone.now() to get the current timezone-aware time.
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:
# middleware.py
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:
# settings.py
MIDDLEWARE = [
# ... other 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')
The Intl.DateTimeFormat().resolvedOptions().timeZone API is supported in all modern browsers and returns IANA timezone strings like "America/Chicago", which are fully compatible with Django and Python's zoneinfo module.
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.