What are UTC, ISO time format and UNIX time and how does Python handle them

“If my time is 16:44, what is that in UTC time?”

“Do we use UTC dates or do we store timezones into the database? And by the way, if I call datetime.now(), am I getting the correct time or should I adjust it with a timezone suffix?".

This time-business is so delicate.

Image for post
Image for post
Photo by La Victorie on Unsplash

I never had much trouble with date-times, until last week, when I had to create a humble Celery task that needs to be a master of time, that needs to understand how all the dates on all these objects relate to one another. And suddenly I am finding myself appalled by all datetimes with no timezone info. What a grievous mistake it was to allow programmers to forget about timezones, to just call now() and hope for the best. How is my super-duper, time-lord of a Celery task supposed to lord the time if a single measly timezone-lacking datetime knocks it out of its balance?

So I had to read a few docs and a few standards to really, truly understand what to do with missing timezones and whether the datetime I am creating is really and truly the exact datetime I want and not one that is 1h before or ahead (my timezone is +01:00, which is very easy to mistake for +00:00).

What is UTC time

UTC is a global time standard. It defined how time will be measured and coordinated between everybody. But UTC is also used as a successor of GMT (=Greenwich Mean Time) to describe the time at the 0° meridian.

In code, we usually denote it with +00:00 or with a Z. The letter Z is used for historical reasons because Z was the name of the timezone using this time. This time is also sometimes called the Zulu time since NATO’s phonetic alphabet for Z is “Zulu”.

The daylight saving time (=DST) does not affect UTC. DST simply modifies the ±[hh]:[mm]-part of the date-time: Europe’s CTE (=Central European Time) is usually described as UTC+1, but during the summer, when DST kicks in, it simply becomes UTC+2.

What is the ISO format / ISO 8601 format

This ISO standard defines how to format dates and date-times without confusion and misunderstandings.

Date format:

  • 2020–10–26

Date and time formats:

  • 2020–10–26T08:15:30+02:00
  • 2020–10–26T08:15:30Z
  • 20201026T081530Z
  • 2020–10–26T08:15:30.456+02:00 <-- with microseconds

If the timezone is omitted, the datetime is usually interpreted to be recording the locale time. But of course, this is up to every programming team to define for themselves.

The T is also often omitted. The ISO standard does allow for this, but only if the 2 parties communicating with such dates have agreed to allow it. However, there is no mention of substituting T with a space. But I think we all see that our community has decided that it can correctly understand a datetime with a space and is actively using it everywhere.

What is UNIX time / Epoch time / POSIX time

Unix time is an integer, it’s the number of seconds passed since 1st January 1970 UTC — a capriciously chosen date. This date is called the Epoch.

UNIX time excludes all leap seconds. It pretends that every day has exactly 24 * 60 * 60 (=86 400) seconds.

Timezones and UTC offsets

UTC offsets are the ±[hh]:[mm] parts of date-time formats. They are a multiple of 15 minutes and they describe the difference between UTC and the locale time.

Python In The World Of Datetime

Python differentiates between naive and aware datetimes. The first one has no timezone, while the second does have a timezone. Each datetime object has an optional tzinfo` attribute, which can hold timezone information.

My current time is 2020-10-26T12:30:10Z, my timezone is +1. Here I get my locale time:

Both above functions create a naive datetime.

Here I create the 31st Dec 2020, at midnight UTC time:

And here I create the 31st Dec 2020, at midnight in the timezone +03:00:

Timezones are set with timdeltea`to describe the UTC offset.

In Python, this format is called “timestamp”. And it is not an integer, but a float, so that microseconds can be represented.

The POSIX time is always the time at UTC+0, which means that when call fromtimestamp with timezone parameter we define only what the timezone of the result will be, not the timezone of the input value. When we passed in UTC+0, it produced the time 11:30, when we passed in UTC+3 it produced 14:30.

Use the `datetime.fromisoformat` for this, BUT: not all ISO 8601 strings can be parsed. Only strings of this format can be parsed:

Using Zas the timezone is not supported.

One way is to use `timedelta`:

The other is to replace parts of the date, but this can trigger ValueError s:

The `replace` function can be used to replace any part of the datetime: minutes, hours, days, timezone, …:

External Sources

Originally published at http://www.ines-panker.com on October 26, 2020.

Software Developer by profession, Explorer by mind. The more I know, the more I understand. http://www.ines-panker.com/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store