Unix 时间戳实际上跟踪什么?

What do Unix timestamps actually track?

我知道 Unix 时间戳定义为自 1970-01-01 00:00:00Z 以来经过的秒数。但是,我找不到给出此定义的明确来源。我还阅读了关于闰秒方面 UTC 和 Unix 时间戳之间关系的各种不同陈述。

This wikipedia page 包含所有闰秒的列表。第一个是

1972-06-30 23:59:60

关于 Unix 时间戳的声明

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

来源: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).

来源:Hacker News, masklinn

我也读过(但我无法再次找到它 - 在 Stack Overflow 的某处),Unix 时间戳假定每天正好有 24*60*60 秒。海报暗示日子仍然以某种方式保持同步,而闰秒只是“减慢”了真正的秒数。因此,“unix 时间戳秒”可能不是 SI 秒。

可能的答案

我可以看到三个可能的答案:

A1:Unix 时间戳跟踪自 1970 年 1 月 1 日以来的 SI 秒 00:00:00Z。这意味着它们与 UTC 相差 27 秒。

A2:Unix 时间戳跟踪“TAI 中经过的秒数”。这意味着将 Unix 时间戳转换为 UTC 的库必须处理闰秒。

A3:Unix 时间戳跟踪“UTC 中经过的秒数”。这意味着在大多数情况下,两个 1 的 Unix 时间戳之间的差异可能是 1 SI 秒,但并非全部。

请为您的答案添加来源。

Python

Pythons datetime 似乎不知道闰秒(?)。

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

并且 time 模块似乎将实际闰秒映射到之前的秒:

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

此印象得到 issue23574 的支持。

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.

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

Unix 时间跟踪自 1970-01-01 00:00:00 UTC 减去 UTCleap seconds 以来经过的 SI 秒数。不计算正闰秒,计算两次负闰秒。换句话说,它算作每天持续 86,400 SI 秒,因此 Unix 时间是 86,400 的倍数对应于午夜 UTC。

没有闰秒的午夜过渡(UTC 一天持续 86,400 SI 秒):

UTC       Second #  Unix time (mod 86,400)
--------  --------  ----------------------
23:59:58  86,398th  86,398
23:59:59  86,399th  86,399
00:00:00  86,400th  86,400

正闰秒的午夜过渡(UTC 一天持续 86,401 SI 秒);到目前为止已经发生了 27 天:

UTC       Second #  Unix time (mod 86,400)
--------  --------  ----------------------
23:59:59  86,399th  86,399
23:59:60  86,400th  86,399 <- positive leap second: not counted in Unix time
00:00:00  86,401th  86,400

负闰秒的午夜过渡(UTC 一天持续 86,399 SI 秒);到目前为止从未发生过:

UTC       Second #  Unix time (mod 86,400)
--------  --------  ----------------------
23:59:57  86,397th  86,397
23:59:58  86,398th  86,398 86,399 <- negative leap second: counted twice in
00:00:00  86,399th  86,400           Unix time

查看此 this answer 了解更多信息。