9

In settings.py I have:

TIME_ZONE = 'Asia/Singapore'
USE_I18N = True
USE_L10N = True
USE_TZ = True

If a user (who is living in Singapore) enters 2013-10-07 01:00 A.M. in a form on my site, the value stored in my (PostgreSQL) database is 2013-10-07 01:00:00+08. When I pull up this information during a python manage.py shell session, I get 2013-10-06 17:00:00+00:00. The same happens when I try to render this information in a template.

What I think is happening: Django recognizes that the user is entering 1:00 A.M. on October 10th, Singapore time, and stores this in the database as 2013-10-07 01:00:00+08. However, when Django retrieves this info from the database, it formats it to UTC time, thereby giving 2013-10-06 17:00:00+00:00.

Do I have that right? And if so, what can I do to make Django display times using the same timezone information that is stored in the database (or at least using my TIME_ZONE setting)? In other words, how can I make it so that the user sees the datetime in the exact same form as she entered it?

GChorn
  • 1,267
  • 1
  • 19
  • 36

2 Answers2

25

I've figured out what's going on. Based on what I had read in the docs here, I was assuming that with USE_TZ=True, Django would output datetimes in the current time zone (which defaults to the TIME_ZONE setting) everywhere--views, the shell, etc.

However, it turns out that Django only makes the conversion in templates, and even then only in the most direct, basic invocation of a datetime object.

Specifically, if you have an object with a DateTimeField and you render its datetime attribute in a template using {{ object.datetime }}, you will get a datetime converted to the current time zone. Yay. However, this functionality won't work for anything else, even within templates, such as {{ object.datetime.hour }} (which will display the hour in UTC). So it's basically just an invisible template tag. Not as magical as I'd hoped!

It looks like I'll need to convert all datetimes to the current time zone in my views before passing them to my templates. I find this kind of weird and counterintuitive considering that my database already has all of the datetimes stored in the time zone I want them displayed in. Wouldn't it make more sense to have to explicitly tell Django you want database values expressed in UTC, than to have Django perform the work automatically and then make you change them back in your views?

EDIT: This answer on SO made the solution to my specific situation considerably easier:

from django.utils.timezone import localtime

result = localtime(some_time_object)

EDIT: It turns out that only PostgreSQL stores time zone information, and that information is separate from the raw datetime values it stores, which are in UTC. So I guess it makes sense for Django to render everything in UTC by default, since other database backends don't even store time zone info.

Community
  • 1
  • 1
GChorn
  • 1,267
  • 1
  • 19
  • 36
  • 1
    Another thing to keep in mind: if you generate an aware datetime which has a tzinfo object associated with it, then save it to Postgres, then retrieve it, the new datetime will be UTC-accurate but won't have the original tzinfo. That means that if you compare the pre-save and saved datetimes with ==, it'll return True, but they aren't the same exact object since the timezones are different. – vaughnkoch Mar 18 '15 at 20:56
  • Mysql also allows storing timezone related info in field. – IJR Jul 07 '15 at 07:24
  • this is working solution, thank you for explaining question as most of the people suggest changing time zone which only affect template – Sadique Khan Feb 24 '22 at 19:17
  • you shouldn't deal with localization in your backend code. As explained in the Django docs, use UTC time in your DB objects, and time aware datetime objects in your code. Just for **displaying** them to the user with parts of that field (like the hour), you can use the `date` template filter: `{{ object.datetime|date:"H" }}` gives you the localized, correct hour. As long as you only use ONE timezone, and your app will NEVER support more than that, your solution works. But keep in mind that someday™ you will need it, and then it'll be hard... So try to make it right from the beginning... – nerdoc Jan 21 '23 at 17:33
2

Have you looked at the localtime template tag

update: However that does refer to setting USE_TZ to True as you have

Community
  • 1
  • 1
rockingskier
  • 9,066
  • 3
  • 40
  • 49