69

My server is located in London.

In my settings.py I have:

TIME_ZONE = 'Europe/Moscow'
USE_TZ = True

But when I execute this:

from django.utils import timezone

print timezone.now().hour

the code prints London's time. What am I doing wrong?

UPDATE:

>> timezone.now()
datetime.datetime(2013, 4, 16, 12, 28, 52, 797923, tzinfo=<UTC>)

Interesting... tzinfo = <UTC>. So maybe it prints not a London time, but UTC's +0 time? Anyway, is there any way to make Django show Moscow time?

Also when I render template with now = timezone.now()

{{ now.hour }} prints 12 (London time)

{{ now|date:"G" }} prints 16 (Moscow time)

imkost
  • 8,033
  • 7
  • 29
  • 47

4 Answers4

119

See question #2 in the "Usage" section of the Django docs.

>>> from django.utils import timezone
>>> timezone.localtime(timezone.now())

Since the doc above also talks about a best practice, including an excerpt below:

How can I obtain the local time in the current time zone?

Well, the first question is, do you really need to?

You should only use local time when you’re interacting with humans, and the template layer provides filters and tags to convert datetimes to the time zone of your choice.

Furthermore, Python knows how to compare aware datetimes, taking into account UTC offsets when necessary. It’s much easier (and possibly faster) to write all your model and view code in UTC. So, in most circumstances, the datetime in UTC returned by django.utils.timezone.now() will be sufficient.

Anupam
  • 14,950
  • 19
  • 67
  • 94
Daniel Hepper
  • 28,981
  • 10
  • 72
  • 75
  • 1
    Could you please tell me how to set auto_add_now as localtime? Thank you very much! – JZAU Mar 07 '14 at 11:15
  • 10
    A little late, but this should work: created = models.DateTimeField(default=lambda: timezone.localtime(timezone.now())) – jeverling May 19 '14 at 19:19
  • 3
    @jeverling Since Django 1.7 it's better not to use lambda in model defaults (it's not supported by migrations). In this case you should define a function and then pass it as a callable as noted [here](http://stackoverflow.com/a/12654998) – sonderlain May 01 '16 at 08:48
  • 2
    I have a doubt..after going through the 'usage link' in the answer, now I feel that I should use default TIME_ZONE ie. UTC in settings.py. So my model's DateTimeField in auto_now_add will use UTC field and everywhere even in code I should use UTC time. Only for rendering time in template, I should use filters/tags to convert UTC to local time. Is my thinking right that I should not change default TIME_ZONE in settings.py..Please clarify whether I am understanding the correct thing or not. – Yusuf Apr 15 '20 at 02:30
  • Very late, but I hard disagree with the recommendation of working purely in UTC until human display. Many times you want to query based on what the user's "day" was 0-24 in local time. It is mentally very hard to reason what the query should look like in pure UTC time when each user sits in a different TZ. – nitsujri Mar 21 '23 at 05:55
4
from django.utils import timezone
time = timezone.localtime() 

It will give your local time that whatever your TIME_ZONE set to.

time = timezone.localtime(timezone.now()) # same result, but it is redundant.
Mason Liu
  • 41
  • 3
1

The reason it works in the template but not in the view python code is somewhat in the docs: https://docs.djangoproject.com/en/3.1/ref/settings/#std:setting-TIME_ZONE

"..... this is the default time zone that Django will use to display datetimes in templates and to interpret datetimes entered in forms."

This is why {{ now|date:"G" }} prints 16 (Moscow time) prints the Moscow time!

Another note is timezone.now() in a normally configured Django app will pick up whatever TIME_ZONE is set to in the settings ('America/New_York' in example below). But can be overridden as well (see below to Paris for example in a middleware or directly in a view for that request)

In [27]: timezone.localtime(timezone.now())

Out[27]: datetime.datetime(2021, 2, 23, 1, 53, 49, 793743, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)

In [29]: timezone.activate(pytz.timezone("Europe/Paris"))

In [30]: timezone.localtime(timezone.now())

Out[30]: datetime.datetime(2021, 2, 23, 7, 54, 19, 21898, tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>)
chachra
  • 769
  • 6
  • 7
0

django's use_tz = True returns datetime object in timezone. if set to false, it uses system default (locale) time which is naïve. I performed a small experiment to clarify this confusion

test1: when use_tz = true; timezone= us/eastern; system timezone: UTC+5:30

datetime.datetime.today() # returned naive datetime with locale time
timezone.now() returned # UTC
timezone.localtime() # returned us/eastern 

test2: when use_tz = true; timezone= us/eastern; system timezone: UTC-5

datetime.datetime.today() # returned naive datetime in with locale time
timezone.now() # returned UTC timezone
timezone.localtime() # in US/eastern timezone

test3: when use_tz = False; timezone= us/eastern; system timezone: UTC-5

timezone.now() # returned naive datetime with system time
timezone.localtime() # returned traceback ValueError: localtime() cannot be applied to a naive datetime

test4: when use_tz = False; timezone= UTC; system timezone: UTC+5:30

datetime.datetime.today() # returned naive datetime in system timezone
timezone.now() # returned naive datetime in system timezone
timezone.localtime() # returned traceback
Aman Bagrecha
  • 406
  • 4
  • 9