Newsletter
TechAnV Blog
Get updates on security engineering, Rust, eBPF, and DevSecOps. No spam, unsubscribe anytime.
Check your inbox and click the confirmation link to complete your subscription.
Show the timezone for datetimes in the Django admin#
Django supports storing dates in a database as UTC but displaying them in some other timezone - which is good. But… by default datetimes are shown in the Django admin interface without any clue as to what timezone they are being displayed in.
This is really confusing. A time may be stored as UTC in the database but in the admin interface it’s displaying in PST, without any visual indication as to what is going on.
I found a pattern today for improving this. You can use django.conf.locale.en.formats to specify a custom date format for a specific locale (thanks, Stack Overflow). Then you can use the e date format option to include a string indicating the timezone that is being displayed, as documented here.
In settings.py do this:
1from django.conf.locale.en import formats as en_formats2
3en_formats.DATETIME_FORMAT = "jS M Y fA e"I added a middleware to force the displayed timezone for every page on my site to America/Los_Angeles like so:
1from django.utils import timezone2import pytz3
4class TimezoneMiddleware:5 def __init__(self, get_response):6 self.get_response = get_response7
8 def __call__(self, request):9 timezone.activate(pytz.timezone("America/Los_Angeles"))10 return self.get_response(request)I put this in a file called core/timezone_middleware.py and added it to my MIDDLEWARE setting in settings.py like so:
1MIDDLEWARE = [2 # ...3 "core.timezone_middleware.TimezoneMiddleware",4]Now datetimes show up in my admin interface looking like this, with a PST suffix:

Showing UTC too#
I decided I’d like to see the UTC time too, just to help me truly understand what had been stored. I did that by adding the following method to my Django model class:
1# Earlier2from django.utils import dateformat3import pytz4
5# Added to the model class:6
7 def created_at_utc(self):8 tz = pytz.UTC9 created_at_utc = timezone.localtime(self.created_at, tz)10 return (11 dateformat.format(created_at_utc, "jS M Y fA e")12 )Then I added created_at_utc to both the list_filter and the readonly_fields tuples in the admin configuration for that model. This caused it to show up in the list view and also as a read-only field at the bottom of the edit view.

Note that I’m calling dateformat.format() in the method and returning a string - this ensures Django’s automatic formatting doesn’t get the chance to convert it back to PST again.