Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Isn't django now() supposed to be in the default time zone?

Tags:

django

This might be a bit of a trivial question, but can't I get django now() to be in the time zone defined in settings.TIME_ZONE?

This is what is actually happening:

>>> from django.utils import timezone
>>> timezone.now()
datetime.datetime(2012, 5, 30, 16, 30, 0, 782087, tzinfo=<UTC>)
>>> timezone.get_default_timezone()
<DstTzInfo 'Asia/Singapore' SMT+6:55:00 STD>
like image 933
Kit Sunde Avatar asked May 30 '12 16:05

Kit Sunde


People also ask

What is the default time zone in Django?

Django's timezone is set to UTC by default.

How does Django use timezone now?

The solution to this problem is to use UTC in the code and use local time only when interacting with end users. Time zone support is disabled by default. To enable it, set USE_TZ = True in your settings file. In Django 5.0, time zone support will be enabled by default.

How do I change the time in Django?

In this scenario, you either have to (1) have users registering supply their timezone, and alter your code, or (2) import django. utils timezone, see this page: django timezone module documentation.


2 Answers

Django's source code (as displayed in the chosen answer) explains the concept of timezone.now():

  1. datetime.now() yields the current time (in your active timezone!) without timezone information ("naive datetime"), whereas ...
  2. timezone.now() always yields the current time in UTC (!) with timezone information.

This is irritating at first sight, yes. They could have decided to yield the current time of the active timezone, but they didn't. You can still use timezone.localtime(timezone.now()) to get what you want:

from django.utils import timezone
from datetime import datetime

timezone.get_current_timezone()
# <DstTzInfo 'Antarctica/McMurdo' LMT+11:39:00 STD>
datetime.now()
# datetime.datetime(2014, 8, 19, 20, 8, 8, 440959)
timezone.localtime(timezone.now())
# datetime.datetime(2014, 8, 19, 20, 8, 14, 889429, tzinfo=<DstTzInfo 'Antarctica/McMurdo' NZST+12:00:00 STD>)
timezone.now()
# datetime.datetime(2014, 8, 19, 8, 8, 22, 273529, tzinfo=<UTC>)
datetime.utcnow()
# datetime.datetime(2014, 8, 19, 8, 8, 29, 769312)

For newcomers and ordinary users timezone.localtime(timezone.now()) is probably the most intuitive. A local time which still retains timezone information.

EDIT: The standard library equivalent for a timezone-aware local time is datetime.now().astimezone(). astimezone applies the system local timezone by default, which allows you to correctly convert any timezone-aware datetime to your local time. To set an arbitrary timezone using timezone names you need the pytz package.

from datetime import datetime, timezone
import pytz

datetime.now()
# datetime.datetime(2022, 9, 14, 5, 26, 35, 146551)
datetime.now().astimezone()
# datetime.datetime(2022, 9, 14, 5, 26, 44, 19645, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200), 'CEST'))
datetime.now(tz=timezone.utc)
# datetime.datetime(2022, 9, 14, 3, 26, 51, 203917, tzinfo=datetime.timezone.utc)
datetime.now(tz=timezone.utc).astimezone()
# datetime.datetime(2022, 9, 14, 5, 26, 58, 546724, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200), 'CEST'))
datetime.now(tz=pytz.timezone('Europe/Kiev'))
# datetime.datetime(2022, 9, 14, 6, 27, 38, 714633, tzinfo=<DstTzInfo 'Europe/Kiev' EEST+3:00:00 DST>)
like image 190
Peterino Avatar answered Oct 17 '22 20:10

Peterino


Or I could just read the source:

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()

Answer is nope, I have to adjust it myself.

like image 44
Kit Sunde Avatar answered Oct 17 '22 21:10

Kit Sunde