A very old question. But I landed here with a similar problem. And while the solution I have may not apply to your use case, it might. Your needs aren't 100% clear in the question.
In my case as I have a website that anyone anywhere can use (as in a website, as that is true of them all) and further that local people can use to manage local events (so in local time) I had also to grapple with timezones in Django.
Now I use Postgresql as a backend and my interests therefore apply to that context. And Postgresql basically stores all datetimes at UTC. That is when I have a local time in the Python code and ask set a Django model field to that then on saving it the timezone information is only used for a conversion to UTC and then lost.
When I then read that field using Django it is in UTC and I can localize it to a timezone, but what timezone? There is the active time zone in Django and that is nice but there are in fact three timezones that are candidates for any context:
The Timezone of the webserver. Least interesting as no end user ever cares per se where the Server is. But the easiest to acquire.
The Timezone of the client. I can and do collect this from the client, that is in JavaScript on page load I callback with the Client's current timezone and make note of for the session (in fact I record it in the users Session data). That is interesting indeed, far more than the webserver's timezone.
The TimeZone of the submitter. Now we're talking business. And this is the most interesting one for me. So I create an event that starts at 7pm Hobart time, and you are using the website in Madrid, and look at the event and you see that it's at 7pm (that is you see Hobart time, the time intended by the creator of the event).
Implementing 3 of course predicates:
- That a submitter have a choice of timezones (and I present this with the login prompt, it being prepopulated with the client's timezone as a default)
- That we record the submitter's preferred timezone with the event.
Now for 1. above you can of course offer an option with every event submission any form field that has a datetime you can offer a Timezone selector too. For my needs that is overkill. A logged in user typically only wants to deal with local times. But exploring remote data it's nice to see it with appropriate times of day (and day as TZ impacts the day too).
The method I employ is as follows:
Any Django model that has a DateTimeField, has a TimeZoneField following it with the exact self same name but with "_tz" appended. This records to timezone of DateTimeField.
I then built a quick custom Transformer:
from django.db.models import Transform, DateTimeField
class DateTimeLocal(Transform):
lookup_name = 'local'
def as_sql(self, compiler, connection):
lhs, params = compiler.compile(self.lhs)
dt = lhs # has quotes like "table_name"."date_time"
tz = lhs[:-1] + "_tz" + lhs[-1] # Add _tz to field name
return f"{dt} AT TIME ZONE {tz}", params
DateTimeField.register_lookup(DateTimeLocal)
And can use it like so:
Blog.objects.filter(created__local>someday)
That is the pseudo-field created__local
is now available (it's a Transform).
The catch is, if you look at the Transform, that it:
Implements Postgresql SQL syntax in as_sql
. I have no idea how portable that is and am dubious that it is very portable.
Predicates the existence of a created_tz
TimeZoneField in the model.
There is some help here: https://docs.djangoproject.com/en/4.0/howto/custom-lookups/