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.