Dates And Time In Python

Page Contents

References

Introduction

The referenced article, "The Science Of Timekeeping", gives a really nice introduction to time and the history of how we measure time. Combined with the reference WC3 article we can get an idea of how our concept of time originated from observable phenomena like sunrise and sunset, the seasons etc, and how now it is based on more abstract standards like the the transition between the two hyperfine levels of the ground state of the cesium-133 atom.

All of this is important for us to realise that there is no really universal definition of time that is the same all over the world, except for something called UTC.

Countries have their own timezones, not all of which differ in a regular pattern, where daylight saving time (DST) may be active or not depending on the time of year, and worse, there are crazy things like leap days end even leap seconds!

In 1884, ... the Greenwich observatory was accepted as source of the world’s standard time ...

... GMT has evolved to UTC ... GMT was based on mean solar time. UTC is based on a definition of the second that is nearly a million times more accurate ... based on a quantum resonance within a caesium atom ...

... UTC is established by the Bureau International des Poids et Mesures (BIPM) based on an a aggregate of data from timing laboratories throughout the world, and from input from the International Earth Rotation Service (IERS).

"Computerphile" gives a really good summary:

Using Dates & Times in Python

The referenced articles by Julien Danjou and Armin Ronacher both make the following very poinient point: Python datetime objects, by default are not timezone aware!. This can be read directly from the Python docs, but wasn't something I'd taken enough notice of until reading those articles!

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.

...

For applications requiring aware objects, datetime and time objects have an optional time zone information attribute, tzinfo, that can be set to an instance of a subclass of the abstract tzinfo class. These tzinfo objects capture information about the offset from UTC time, the time zone name, and whether Daylight Saving Time is in effect.

Thus, when using dates/time in Python always use aware objects so that there is no ambiguity in what time is being represented and always store time in UTC: An aware current UTC datetime can be obtained by calling datetime.now(pytz.utc). Why do we want to do this? As Danjou points out, without this the datetime object will have no timezone information, so later on in the code, can we be sure it is representing a time in UTC? There would be no way to tell! He suggests treating any datetime without a timezone as a bug!

Never use unware datetime objects. Always make sure you get timezone aware objects and even better objects using UTC with the timezone information set to UTC: datetime.now(pytz.utc)!

As Danjou recommends, as well as using aware datetime objects you should also store and retreive dates/times in ISO 8601 format by using datetime.datetime.isoformat().

To store and retreive date/time use ISO 8601 format, supported by the Python iso8601 package.

Examples

Get The Current Time as UTC

>>> import datetime
>>> import pytz
>>> datetime.datetime.now(pytz.utc)
datetime.datetime(2018, 3, 18, 12, 36, 52, 315868, tzinfo=<UTC>)

Output Current Time In ISO 8601 Format

>>> import datetime
>>> import pytz
>>> datetime.datetime.now(pytz.utc).isoformat()
'2018-03-18T12:41:07.591469+00:00'

Input Current Time In ISO 8601 Format

>>> import datetime
>>> import pytz
>>> import iso8601
>>> a = datetime.datetime.now(pytz.utc).isoformat()
>>> a
'2018-03-19T07:53:48.225000+00:00'
>>> iso8601.parse_date(a)
datetime.datetime(2018, 3, 19, 7, 53, 48, 225000, tzinfo=<FixedOffset '+00:00' datetime.timedelta(0)>)