pythondatetimeunix-timestampleap-second

What do Unix timestamps actually track?


I know that the Unix timestamp is defined as the number of seconds passed since 1970-01-01 00:00:00Z. However, I could not find a clear source that gives this definition. I've also read various different statements about the relationship between UTC and the Unix Timestamp in regards to leap seconds.

This wikipedia page contains a list of all leap seconds. The first one is

1972-06-30 23:59:60

Statements about Unix timestamps

As for "all modern computer systems", Unix time is completely ignorant about anything except seconds.

Source: HackerNews, brazzy

UNIX time tracks UTC instead of TAI meaning it "corrects" for leap seconds. As a result, UNIX time is not "the number of seconds since epoch" but "86400 * (number of whole days since epoch) + (number of seconds since midnight)", and UNIX time will go forwards (never so far) and backwards on leap seconds (a second will repeat in most implementations as the day goes from 23:59:60 to 00:00:00, as they have the same timestamp).

Source: Hacker News, masklinn

I've also read (but I can't find it again - somewhere on Stack Overflow) that Unix Timestamps assume each day has exactly 24*60*60 seconds. The poster implied that days are still somehow kept synchronously while the leap seconds simply "slows down" the real second. Hence a "unix timestamp second" might not be a SI second.

Possible answers

I can see three possible answers:

A1: Unix Timestamps track SI seconds since 1970-01-01 00:00:00Z. This means they are 27 seconds off from the UTC.

A2: Unix Timestamps track "passed seconds in TAI". This means a library that converts Unix timestamps to UTC has to deal with leap seconds.

A3: Unix Timestamps track "passed seconds in UTC". This means that a difference between two Unix timestamps of 1 might be 1 SI-second in most cases, but not in all.

Please add a source to your answer.

Python

Pythons datetime seems not to be aware of leap seconds (?).

>>> import datetime
>>> a = datetime.datetime(1972, 6, 30, 23, 59, 59)
>>> b = datetime.datetime(1972, 7, 1, 0, 0, 0)
>>> b-a
datetime.timedelta(0, 1)

and the time module seems to map the actual leap second on the second before:

>>> import time
>>> t3 = time.mktime((1972, 6, 30, 23, 59, 59, -1, -1, -1))
>>> t4 = time.mktime((1972, 7, 1, 0, 0, 0, -1, -1, -1))
>>> t4 - t3
1.0
>>> t4 = time.mktime((1972, 6, 30, 23, 59, 60, -1, -1, -1))
>>> t4 - t3
1.0

This impression is supported by issue23574.


Solution

  • A.4.16 Seconds Since the Epoch

    Coordinated Universal Time (UTC) includes leap seconds. However, in POSIX time (seconds since the Epoch), leap seconds are ignored (not applied) to provide an easy and compatible method of computing time differences. Broken-down POSIX time is therefore not necessarily UTC, despite its appearance. [...]

    Most systems' notion of "time" is that of a continuously increasing value, so this value should increase even during leap seconds. However, not only do most systems not keep track of leap seconds, but most systems are probably not synchronized to any standard time reference. Therefore, it is inappropriate to require that a time represented as seconds since the Epoch precisely represent the number of seconds between the referenced time and the Epoch.

    It is sufficient to require that applications be allowed to treat this time as if it represented the number of seconds between the referenced time and the Epoch. It is the responsibility of the vendor of the system, and the administrator of the system, to ensure that this value represents the number of seconds between the referenced time and the Epoch as closely as necessary for the application being run on that system.

    Source: http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16