You have to be careful when you talk about, or use, datetimes. There are basically two types: naive and aware. From the Python docs:
There are two kinds of date and time objects: “naive” and “aware”.
An aware object has sufficient knowledge of applicable algorithmic and political time adjustments, such as time zone and daylight saving time information, to locate itself relative to other aware objects. An aware object is used to represent a specific moment in time that is not open to interpretation.
A naive object does not contain enough information to unambiguously locate itself relative to other date/time objects. Whether a naive object represents Coordinated Universal Time (UTC), local time, or time in some other timezone is purely up to the program, just like it is up to the program whether a particular number represents metres, miles, or mass. Naive objects are easy to understand and to work with, at the cost of ignoring some aspects of reality.
now()
and utcnow()
both return aware datetime objects. However, when you use the strptime()
function, whether the datetime object created is naive or aware depends on the format. E.g.:
{{ strptime('2019-04-26 10:00:00', '%Y-%m-%d %H:%M:%S') }}
{{ strptime('2019-04-26 10:00:00 +1000', '%Y-%m-%d %H:%M:%S %z') }}
{{ strptime('2019-04-26 10:00:00', '%Y-%m-%d %H:%M:%S').tzinfo }}
{{ strptime('2019-04-26 10:00:00 +1000', '%Y-%m-%d %H:%M:%S %z').tzinfo }}
{{ strptime('2019-04-26 10:00:00', '%Y-%m-%d %H:%M:%S').timestamp() }}
{{ strptime('2019-04-26 10:00:00 +1000', '%Y-%m-%d %H:%M:%S %z').timestamp() }}
in my case results in:
2019-04-26 10:00:00
2019-04-26 10:00:00+10:00
None
UTC+10:00
1556290800.0
1556236800.0
The first does not specify a time zone, and the second does. (I’m using your time zone on purpose here instead of mine to show what happens if the OS’s time zone is different than what it should be.) So you can see the first is a naive object, whereas the second is an aware object.
The next two lines show the tzinfo for the first two. Again, no time zone info for the first, and the second is your time zone.
The last two get the Unix timestamp for the first two. Notice how they are different? But they should be the same, right? The reason they are different is because the first is a naive datetime object, so when the timestamp method is called, it gets the time zone from the “OS”, which, of course, in my case is “wrong” because it is not your time zone, but rather -0500 (or CDT.) And using the Unix timestamp website (which takes a UTC time, so to be equivalent to 10:00am in your time zone, I had to use 12:00am UTC):
Notice how the returned timestamp from the templates is only correct when an aware datetime object is used. (It would also have been correct if the OS’s time zone was the “correct” time zone.)
So, bottom line, if you create naive datetime objects in your templates, and you want to get a timestamp from them, or want to compare them to aware datetime objects, then the time zone in the “OS” must be correct.
EDIT: Actually, you can’t compare aware and naive datetimes:
>>> datetime.strptime('2019-04-26 10:00:00', '%Y-%m-%d %H:%M:%S') > datetime.strptime('2019-04-26 10:00:00 +1000', '%Y-%m-%d %H:%M:%S %z')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes