![时区](https://linux22.com/image/230495/%E6%97%B6%E5%8C%BA.png)
读完论文后,我问自己,到 2035 年左右,我们,地球上的人和我们的计算机,可能不得不将我们的时间向后修正一秒以符合天文时间。
当我读到这篇文章时,我首先相信这会给计算机带来很大的麻烦:一个可以倒退并重播已经存在的秒的时钟不会被许多程序支持,首先是:操作系统。
但后来我发现我们每年都会做类似的事情:我们在应用冬令时时会倒退一小时。我不知道每个国家是否都一样,但是凌晨3点我们决定是2点。
2024-10-27 02:59:59.999999
当这个时间发生变化并且时间戳从到 时,Linux 操作系统如何管理带时间戳的操作2024-10-27 02:00:00.000000
?例如,每条按时间排序的消息都应该被欺骗。
但也许这不是正在发生的事情,从2024-10-27 02:59:59.999999
到2024-10-27 02:00:00.000000
仍然在进行,就系统时间戳而言,从1730069999
到1730070000
(+1)(以秒为单位)?
在这种情况下,在 2035 年,将我们的时间缩短一秒的问题与我们每年所做的向后一小时的问题会有所不同吗?例如,它可能导致我们分配:
2019682799 = 2034-12-31 23:59.59
,
2019682800 = 2035-01-01 00:00.00
,
2019682801 = 2035-01-01 00:00.00
2019682802 = 2035-01-01 00:00.01
但这里的问题是:
具有正确操作系统的计算机将遇到未经校正的计算机(太旧或未更新的操作系统),相信:
2019682801 = 2035-01-01 00:00.01
但2019682802 = 2035-01-01 00:00.02
事实并非如此。但是,如果某些操作系统仍然存在,不知道夏令时和冬令时的变化,这也是同样的问题。我想世界上这样的代码示例并不多:
timestamp = System.timeInMillis() millis = millis % 1000 secondsSince1970 = millis / 1000 seconds = secondsSince1970 % 60 minutesSince1970 = ...
因为在这里,
seconds
如果应用第二次删除,变量在 2035 年就会变得错误,因为2019682802
应该导致01
而不是导致02
。
答案1
在 Linux 中,操作系统维护一个基本上以 UTC 时间运行的时钟,没有夏令时变化。
(通常)一小时的夏令时由不更改时钟,但更改显示本地时间时应用于其的 UTC 偏移量。
因此,例如在中欧时区,时间戳
2024-10-27 02:59:59.999999 UTC+2 = 2024-10-27 00:59:59.999999 UTC = 1730001599
后面会跟上时间戳
2024-10-27 02:00:00.000000 UTC+1 = 2024-10-27 01:00:00.000000 UTC = 1730001600
(请注意,我在这里没有使用 POSIX 时区说明符:由于 POSIX 规范所基于的系统主要是在美国开发的,并且它们为自己保留正整数时区说明符,因此 POSIX 时区偏移量的符号与您可能的相反期望基于对 UTC 偏移的一般理解。)
这就是为什么,如果程序必须以本地时间格式存储时间戳,那么它应始终包含一些 UTC 偏移标识符与时间戳一起。如果程序需要在夏令时结束时避免人类尺度的歧义,则它应该始终以某种 UTC 等效格式在内部存储时间戳。
“将 UTC 时间向后移动一秒”相当于在时间刻度中额外插入一秒。这不是什么新鲜事,并且 UTC 时间标准已经有一个标准方法来做到这一点:闰秒。每年六月底和十二月底(UTC),都有机会插入闰秒,例如
xxxx-12-31 23:59:59 UTC
接下来将是
xxxx-12-31 23:59:60 UTC
然后通过
(xxxx+1)-01-01 00:00:00 UTC
这是否真正实现取决于国际组织 IERS 所决定的地球自转的可测量缺陷。
上次插入闰秒是在 2016 年底:
https://hpiers.obspm.fr/eoppc/bul/bulc/UTC-TAI.history
目前,没有计划在 2024 年 6 月下旬插入闰秒。下一次插入闰秒的权威来源是 IERS Bulletin C:
https://datacenter.iers.org/data/latestVersion/bulletinC.txt
NTP 时间同步协议具有闰秒公告功能来解决此问题。 Linuxdate
命令将在适当的时间尽职尽责地显示 23:59:60 UTC 时间戳,以证明操作系统知道正在发生的事情,但显然这意味着并非所有 Unix 时间戳秒的长度都相等:在插入闰秒时,大多数操作系统都会考虑Unix 时间秒被拉伸到两秒的长度。
(NTP 还具有“负闰秒”功能,但到目前为止,实践中从未需要这样做,并且预计在可预见的将来也不需要。)
一个更新的替代实用解决方案是跳跃涂抹:额外的一秒是通过减慢系统时钟来处理的,这样额外的一秒将在一天左右的时间内被计算在内。这是基于这样的想法:每秒长度的均匀性比 +/-1 秒范围内的时间戳的绝对精度更重要。对于大多数“通用”时间用途来说,它可能是一个有效的解决方案。
对于那些始终需要亚秒级计时精度,或者在超过半年左右的所有时间跨度内精确计算秒数的人来说,闰秒显然是一个问题。然而,事实证明,需要这种准确性的人大多已经意识到了这一事实,并且已经在处理它了。
如果您需要在 Linux/Unix 系统中进行如此高精度的计时,您可以设置一个本地时间同步设施(例如修改后的 NTP 服务器)来分发 TAI(国际原子时间)而不是 UTC。然后,您可以让系统时钟以 TAI 而不是 UTC 运行,并使用right/
IANA/Olson 时区数据库中的时区变体(即,right/Europe/Paris
而不仅仅是Europe/Paris
:这些将包括闰秒)。
答案2
这里已经有很多好的答案,但我没有看到提到一个更平淡的事实:这种第二转变发生了每时每刻已经在您的计算机上。有时这种转变甚至不止一秒——但这没关系。
您会发现,普通 PC/服务器中的硬件时钟是出了名的不精确。如果没有频繁的时钟同步,它们将整体漂移分钟每年。资料来源:我不止一次看到/不得不处理过这个问题,无论是在家用电脑还是服务器上。
我不知道制造一个全年稳定的时钟是否太困难/太昂贵,但我的猜测是 NTP 是一个简单而有效的解决方案,因此不需要更精确的硬件时钟。至少在正常情况下不会。
而且 - 正如您可能已经注意到的 - 我们所有的计算机对此都完全没问题。事实上,这与手动更改计算机上的时钟没有什么不同。顺便说一句 - 这是另一个可能会严重扰乱时钟的操作,但不会造成任何问题。
现实情况是,大多数程序并不关心时钟的移动。如果他们需要一个稳定的单调时钟(就像计算机游戏计算在框架中绘制什么),操作系统中有单独的功能。它们不返回时间戳,而是返回“计算机启动后的纳秒”或类似的内容。非常适合测量两个事件之间经过的时间。
时间戳通常用于日志记录或其他精度不那么重要的地方。您始终需要实际的毫秒级精确时间戳的情况非常罕见。
添加:刚刚想起另一个时钟疯狂跳跃的场景:当您的计算机进入睡眠或休眠模式并随后唤醒时。现在这实际上是某些应用程序无法处理这种操作,但即使如此,这种情况也相当罕见。显然操作系统是好的。
添加2:TL;DR - 操作系统/应用程序级别对闰秒的支持是无关紧要的。重要的是对时钟同步的支持。只要计算机能够成功地将其时钟与某个外部时间源同步,它就会理所当然地拾取闰秒,甚至不会注意到任何异常情况。如今,时钟同步已成为所有设备上的标准,并且默认启用。
添加了 3 个:我并不是说这永远不会造成任何问题。显然,在适当的情况下这可能是一个问题。只是在实践中这种情况非常罕见。
答案3
我不会在其他答案中添加任何新内容,但我会尝试更加简洁和清晰。
时区
计算机的实际硬件时钟显示自纪元 (1970-01-01 00:00:00 UTC) 以来的时间(以秒为单位)。系统本身,通过一些glibc库(比如strftime(3)
)知道如何将其转换为特定时区中人类可读的时间。
例如,在美国/太平洋时区,您可以使用以下命令检查 2024 年时区的变化时间:zdump
命令:
$ zdump -V -c 2024,2025 US/Pacific
US/Pacific Sun Mar 10 09:59:59 2024 UT = Sun Mar 10 01:59:59 2024 PST isdst=0 gmtoff=-28800
US/Pacific Sun Mar 10 10:00:00 2024 UT = Sun Mar 10 03:00:00 2024 PDT isdst=1 gmtoff=-25200
US/Pacific Sun Nov 3 08:59:59 2024 UT = Sun Nov 3 01:59:59 2024 PDT isdst=1 gmtoff=-25200
US/Pacific Sun Nov 3 09:00:00 2024 UT = Sun Nov 3 01:00:00 2024 PST isdst=0 gmtoff=-28800
因此,如果我们想将其转换为自 EPOCH 以来的秒数,可以使用以下命令:
$ date --date='Sun Mar 10 01:59:59 PST 2024' +%s
1710064799
因此,在太平洋标准时间的这个特定时间,将会有1710064799自纪元 (1970-01-01 00:00:00 UTC) 以来经过的秒数。
现在,如果您在这一秒检查美国/太平洋时间,您将看到:
$ TZ=US/Pacific date --date='@1710064799'
Sun Mar 10 01:59:59 PST 2024
这仍然是 PST(太平洋标准时间)。但如果你只添加一秒钟:
$ TZ=US/Pacific date --date='@1710064800'
Sun Mar 10 03:00:00 PDT 2024
可以看到它“跳”了一小时,从 02:00 到 03:00,时区也从 PST(太平洋标准时间)切换到 PDT(太平洋夏令时间)。硬件时钟中的秒数仍然以相同的方式运行,只是人类表示(取决于您的特定时区)发生了变化。
闰秒
您的系统首先如何获得正确的时间?它使用 NTP(网络时间同步协议)从某些时间服务器(通常是路由器)轮询正确的时间。当本地硬件时钟与从时间服务器轮询的时间存在差异时,它还会使用不同的算法来同步时间。然后 NTP 服务器的工作就是添加或删除闰秒。为此有不同的方法。
例如,在思科路由器,闰秒被添加或删除到该月的最后一秒。
vl-7500-6#显示时钟 世界标准时间 2006 年 12 月 31 日星期日 23:59:59.123 vl-7500-6#显示时钟 世界标准时间 2006 年 12 月 31 日星期日 23:59:59.627 << 第 59 秒出现两次 vl-7500-6#显示时钟 世界标准时间 2006 年 12 月 31 日星期日 23:59:59.131 vl-7500-6#显示时钟 世界标准时间 2006 年 12 月 31 日星期日 23:59:59.627
谷歌使用一个跳跃涂片方法,即闰秒前的最后一天,每一秒都会变慢或变快,直到在 24 小时结束时将添加/删除的闰秒完全加起来。
在此示例中,我们假设 2022 年 12 月末有闰秒,但实际时间表尚未公布。
涂抹期从 2022-12-31 12:00:00 UTC 开始,持续到 2023-01-01 12:00:00 UTC。在此期间之前和之后,污迹时钟和时间服务与应用闰秒的时钟一致。
在涂片过程中,时钟的运行速度比平时稍慢。涂抹时间尺度中的每一秒时间大约长 11.6 μs比陆地时间中实现的 SI 秒还要多。
[...]
在 86,401 SI 秒的涂抹过程中,86,400 指示秒中的拉伸加起来就是跳跃所需的额外 SI 秒。
答案4
当地时间纯粹是一个问题表示层。它不是 Unix 时间或任何远程现代系统上的时间数据模型的一部分(甚至现代 Windows 也支持将硬件时钟保持为 UTC)。这意味着事件是相对于彼此进行全局排序的(除了某些处理闰秒的模式,这就是为什么它们很难且有争议的原因),并且每个用户(甚至每个进程)都可以有自己的想法显示时间。具有不同策略的系统之间的时间可以在表示层显示时间的方式上进行比较,无论系统位于不同的时区,还是只是有喜欢在不同时区工作或使用 UTC 的用户。