How do I get the visitor's current timezone then convert timezone.now() to string of the local time in Django 1.4?
Solution 1
You need to read the Django Timezones docs carefully.
One important point:
there's no equivalent of the Accept-Language HTTP header that Django could use to determine the user's time zone automatically.
You have to ask the user what their timezone is or just use a default.
You also need to make sure:
USE_TZ = True
in your settings.py
.
Once you have a timezone tz
, you can:
from django.utils import timezone
timezone.activate(tz)
datetime = timezone.now() if checked else None
to get a timezone-aware datetime
object in timezone tz
.
Solution 2
While the browser does not send any headers to the server that would indicate a timezone, the JavaScript environment does know its current timezone.
This has two important effects: While the server can't find out your current timezone on the initial request, you can send down some javascript code which will determine the TZ offset and send that information back to the server so that the zone info can be associated with the current session from that point forward.
But more importantly, if you're sending your time value inside JSON data which will be interpreted by the browser client-side, the browser's timezone doesn't need to be known. Instead, you only have to ensure the timezone offset is present in your JSON output so that the browser can do its own timezone math after-the-fact.
var now = new Date()
var offset_minutes = now.getTimezoneOffset() # e.g. 240 for GMT-0400
Solution 3
Since you want the users' timezones, it makes sense to me that this should be done on the browser with Javascript.
I pass something like this into the template:
{"t": str(obj.timestamp))
Where obj is an instance of a django model where the timestamp field is of type DateTimeField.
The template:
<div class="timestring">{{ t }}</div>
...
<script>
$('.timestring').each(function(){
var d = new Date($(this).text());
$(this).text(d.toLocaleDateString() + ", " + d.toLocaleFormat("%r (%Z)"));
})
</script>
For me, this outputs something like: 2/15/2017, 05:22:24 PM (PST)
The relevant documentation:
Javascript Date class (see especially the constructor which accepts datestrings, and the toLocaleFormat() method)
hobbes3
Updated on June 26, 2022Comments
-
hobbes3 almost 2 years
I understand that the best practice now with Django 1.4 is to store all
datetime
in UTC and I agree with that. I also understand that all timezone conversation should be done in the template level like this:{% load tz %} {% timezone "Europe/Paris" %} Paris time: {{ value }} {% endtimezone %}
However, I need to convert the UTC time to the
request
's local time all in Python. I can't use the template tags since I am returning the string in JSON using Ajax (more specifically Dajaxice).Currently this is my code
ajax.py
:# checked is from the checkbox's this.value (Javascript). datetime = timezone.now() if checked else None $ order_pk is sent to the Ajax function. order = Order.objects.get(pk=order_pk) order.time = datetime order.save() return simplejson.dumps({ 'error': False, 'datetime': dateformat.format(datetime, 'F j, Y, P') if checked else 'None' })
So even if the current time is
April 14, 2012, 5:52 p.m.
in EST time (my local timezone), the JSON response will returnApril 14, 2012, 9:52 p.m
, because that is the UTC time.Also I noticed that Django stores a template variable called
TIME_ZONE
for each request (not actually part of therequest
variable), so since my isAmerica/New_York
, I'm assuming that Django can figure out each visitor's own local timezone (based on HTTP header)?Anyway, so my question is two-fold:
- How do I get the visitor's local timezone in my
ajax.py
? (Probably pass it as a string argument like{{ TIME_ZONE }}
) - With the visitor's local timezone, how to convert the UTC
timezone.now()
to the local timezone and output as a string using Django'sdateformat
?
EDIT: for @agf
timezone.now()
gives the UTC time whenUSE_TZ = True
:# From django.utils.timezone def now(): """ Returns an aware or naive datetime.datetime, depending on settings.USE_TZ. """ if settings.USE_TZ: # timeit shows that datetime.now(tz=utc) is 24% slower return datetime.utcnow().replace(tzinfo=utc) else: return datetime.now()
Is there anyway to convert a
datetime
to something other than UTC? For example, can I do something likecurrent_time = timezone.now()
, thencurrent_time.replace(tzinfo=est)
(EST = Eastern Standard Time)? - How do I get the visitor's local timezone in my
-
hobbes3 about 12 yearsWell I'll first have to do
timezone.now()
beforetimezone.activate(tz)
and store that toorder
first right? But then there will be 2 differentdatetime
. -
agf about 12 years@hobbes3 if you want a timezone-aware datetime for the default timezone, then yes. If you want a timezone-aware UTC datetime, and the default timezone isn't UTC, then use you need to convert to UTC.
-
agf about 12 years@hobbes3 You can always use
somedatetime.replace(tz=sometz)
. -
hobbes3 about 12 yearsYa, sorry I just realized my first comment is very ambiguous. I meant to say that I want to first capture the currnent UTC time with
current_time = timezone.now()
, attach that toorder
(store it to the database), then use the samecurrent_time
, convert it to ETC or whatever timezone the visitor uses, then convert that to a string, and finally pass it back to JavaScript via Ajax. I hope that made sense. -
agf about 12 years@hobbes3 If you want the current UTC time, use
datetime.datetime.utcnow().replace(tz=utc)
for that (right from the docs I linked), andtimezone.now()
for the current local time. -
hobbes3 about 12 yearsActually I already have
USE_TZ = True
andTIME_ZONE = 'America/New_York'
andtimezone.now()
gives the UTC time. -
agf about 12 years@hobbes3 You still have to
timezone.activate(tz)
as I showed in my post.timezone.now()
gives a timezone-awaredatetime
, even in UTC, but that doesn't mean it always uses the local time. -
hobbes3 about 12 yearsOh so you're saying, use
timezone.activate(tz)
, then dotimezone.now()
to get the local time, then convert that to UTC and store that in the database? -
agf about 12 years@hobbes3 I was assuming that since what you're sending through JSON is for display only, it doesn't have to match the time stored in the database down to the microsecond, so it's perfectly safe to use two different
datetime
objects so you don't have to convert back-and-forth between UTC and the local timezone at all. However, you can always usereplace(tz=thetz)
in either direction, but the purpose oftimezone.now()
as a convenience function is to be able to give you a timezone aware local time easily.