Unix 时间/官方时间在哪里测量?

UTF*_*F-8 22 timestamps time

免责声明:

我刚刚浏览了 StackExchange 站点列表大约 20 分钟,试图找出发布此内容的位置。如果您知道任何更合适的网站,请将这个问题移到那里。我在这里发布这个是因为 unix 时间让我思考。


众所周知,有 unix 时间和 UTC。Unix 时间一直在滴答作响,计算秒数——每秒一秒——而 UTC 试图以我们使用的人类可读格式来保持时间,与地球自转的相位保持一致。为此,UTC 会不时插入闰秒。

由于时间与经历时间的物体所受到的重力、其他类型的加速度和相对速度有关,这导致了 2 个问题。让我们先解决一个简单的问题:unix 时间在哪里测量?如果 Alice 和 Bob 开始同意当前时间是 1467932496.42732894722748,当他们在同一个地方时(当然,一秒被定义为 9'192'631'770 辐射周期,对应于铯 133 的两个能级之间的跃迁)原子在静止和 0 K),由于爱丽丝生活在海平面上而鲍勃生活在高山上,或者爱丽丝生活在北极而鲍勃生活在赤道,因此遇到了双重悖论,他们不会再同意了。那么unix时间是如何精确定义的呢?

一开始您可能看不到 UTC 的问题,因为每个人都可以就地球何时完成轨道运行达成一致(这当然忽略了大陆板块运动,但我认为我们已经很好地解决了这个问题,因为使用 GPS 可以测量它们的运动非常精确,我们可以假设它们处于我们模型中的固定位置,并且不会随着大陆板块的移动而移动),无论它们是在山上、海平面上、赤道上还是在北极。可能会有一些时差,但它们不会累积。

但是一秒被定义为 9'192'631'770 个辐射周期,对应于静止和 0 K 时铯 133 原子的两个能级之间的跃迁,铯 133 原子不关心地球轨道。因此,UTC 决定在何处插入闰秒,但必须在地球轨道相位与原子钟某处测量的时间之间存在测量或预测的偏移。那是什么地方?

hob*_*bbs 32

你的标题问题没有真正的答案;Unix 时间不是真正的时间刻度,也不是在任何地方“测量”的。它是 UTC 的一种表示,尽管它很糟糕,因为 UTC 中存在它无法表示的时刻。Unix 时间坚持每天有 86,400 秒,但 UTC 由于闰秒而偏离了这一点。

至于你更广泛的问题,有四个重要的时间尺度:

  1. UT1(世界时),由世界各地的天文台计算,这些天文台测量地球相对于固定恒星的自转。通过这些观察和一些数学运算,我们得到了旧格林威治标准时间的更现代版本,该标准基于格林威治皇家天文台的太阳正午时刻。世界时由一个名为IERS(国际地球自转和参考系统服务,前身为国际地球自转服务)的组织计算。

  2. TAI(国际原子时),由世界各地的数百个原子钟保存,由国家标准机构等维护。为 TAI 做出贡献的时钟管理员使用时间传输技术将他们的时钟相互引导,消除单个时钟的任何小错误并创建集合时间;这个集合是 TAI,由国际度量衡局 (BIPM) 发布,它是 SI 单位制的管理者。为了回答您关于时间膨胀的问题,TAI 被定义为海平面上的原子时间(实际上,在大地水准面,这是同一想法的更高级版本),并且每个时钟都会针对其自身高度的影响进行校正。

  3. UTC(协调世界时),在 1972 年 1 月 1 日被设置为比 TAI 晚十秒,并且从那一天起,它以与 TAI 完全相同的速度向前跳动,除非添加或减去闰秒。IERS 决定宣布闰秒,以便将差异保持在 0.9 秒内(实际上,在大约 0.6 秒内;增加的闰秒会导致差异从 0.6 变为 +0.4)。理论上,闰秒可以是正值也可以是负值,但由于地球的自转速度比 SI 和 TAI 制定的标准要慢,负闰秒从来没有必要,也可能永远不会。

  4. Unix time,它尽力将 UTC 表示为单个数字。每个 86,400 倍数的 Unix 时间都对应于 UTC 午夜。由于并非所有 UTC 天都是 86,400 秒,但所有“Unix 天”都是,因此必须以某种方式修补不可调和的差异。没有对应于增加的闰秒的 Unix 时间。在实践中,系统要么表现得好像前一秒发生了两次(unix 时间戳向后跳一秒,然后再向前跳),要么应用像跳跃涂抹这样的技术,在任何一侧扭曲时间更长的时间。闰秒。在任何一种情况下都有一些不准确,尽管至少第二个是单调的。在这两种情况下,ab不等于b一个; 它等于ba 加上中间闰秒的数量

由于 UT1、TAI、UTC 和 IERS 都是全球性的、多国努力的,因此没有单一的“在哪里”,尽管巴黎天文台发布了 IERS 公告并且 BIPM 也设在巴黎,这是一个答案。需要精确、可追溯时间的组织可能会将其时基表述为“UTC(USNO)”之类的内容,这意味着它们的时间戳采用 UTC 并且它们来自美国海军天文台的时间,但考虑到以下问题我提到过 Unix 时间,它基本上与那个精度级别不兼容——任何处理真正精确时间的人都会有 Unix 时间的替代品。


Bil*_*hor 13

时钟的调整由 IERS 协调。他们根据需要安排在时间流中插入闰秒。

来自NTP 时间刻度和闰秒

巴黎天文台的国际地球自转服务(IERS) 使用 USNO 和其他天文台提供的天文观测来确定 UT1(导航器)时间刻度,该时间刻度已针对地球自转的不规则变化进行了校正。

据我所知,23:59:60(闰秒)和第二天的 00:00:00 在 Unix 时间中被认为是同一秒。


Jde*_*eBP 13

UNIX 时间是在运行 UNIX 的计算机上测量的。

这个答案希望您知道协调世界时 (UTC)、国际原子时 (TAI) 和 SI 秒是什么。解释它们远远超出了 Unix 和 Linux Stack Exchange 的范围。 这不是物理或天文学堆栈交换。

硬件

您的计算机包含驱动时钟和定时器的各种振荡器。它的确切内容因计算机而异,具体取决于其体系结构。但通常,并且在非常笼统的情况下:

  • 某处有一个可编程间隔计时器(PIT),可以对其进行编程以计算给定数量的振荡并触发对中央处理单元的中断。
  • 中央处理器上有一个周期计数器,它为每个执行的指令周期简单地计数 1。

操作理论,非常广泛的术语

操作系统内核使用 PIT 来生成滴答声。它将 PIT 设置为自由运行,在例如百分之一秒的时间间隔内计算正确的振荡次数,生成中断,然后自动重置计数以再次运行。对此有多种变化,但本质上这会导致以固定频率引发滴答中断。

在软件中,内核每滴答增加一个计数器。它知道滴答频率,因为它首先对 PIT 进行了编程。所以它知道一秒钟有多少滴答作响。它可以使用它来知道何时增加计数秒的计数器。后者是内核的“UNIX 时间”概念。事实上,如果留给自己的设备,它确实会以每 SI 秒 1 的速率向上计数。

有四件事使这变得复杂,我将用非常笼统的术语来介绍。

硬件并不完美。一个 PIT 的数据表说它具有N赫兹的振荡器频率,可能会改为具有(例如)N .00002 赫兹的频率,结果很明显。

该方案与电源管理的互操作性非常差,因为 CPU 每秒唤醒数百次,所做的只是增加变量中的一个数字。因此,某些操作系统具有所谓的“无滴答”设计。内核不是让 PIT 为每个滴答发送一个中断,而是计算(从低级调度程序)在没有线程量用完的情况下将要经过多少滴答,并对 PIT 进行编程以将那么多滴答记入发出滴答中断之前的未来。它知道它必须在下一个滴答中断时记录N 个滴答的经过,而不是 1 个滴答。

应用软件有能力改变内核的当前时间。它可以步进值,也可以转换值。回转涉及调整必须经过以增加秒计数器的滴答数。于是秒计数器不一定每一个SI的速度算第二无论如何,即使假设完美的振荡器。步进涉及简单地在秒计数器中写入一个新数字,这通常不会发生,直到最后一秒结束后 1 SI 秒。

现代内核不仅计算秒,而且计算纳秒。但是每纳秒一次的滴答中断是荒谬的,而且通常是完全不可行的。这就是周期计数器之类的东西发挥作用的地方。内核会记住每一秒(或每个滴答)的循环计数器值,并且可以从计数器的当前值计算出,当某事想要知道以纳秒为单位的时间时,自上一秒(或打钩)。但是,由于指令周期频率可能会发生变化,因此电源和热管理会对此造成严重破坏,因此内核会依赖其他硬件,例如(例如)高精度事件计时器 (HPET)。

C 语言和 POSIX

C语言的标准库描述了不透明的类型,方面时time_t,结构类型tm与各种指定字段,和不同的库函数等time()mktime()localtime()

简而言之:C 语言本身仅保证它time_t是可用的数字数据类型之一,并且计算时差的唯一可靠方法是difftime()函数。POSIX 标准提供了更严格的保证,time_t它实际上是整数类型之一,并且它从 Epoch 开始计算秒数。它也是指定timespec结构类型的 POSIX 标准。

time()函数有时被描述为系统调用。事实上,它在很长一段时间内都不是许多系统的底层系统调用,现在。例如,在 FreeBSD 上,底层系统调用是clock_gettime(),它有各种可用的“时钟”,以各种方式以秒或秒+纳秒为单位进行测量。正是这个系统调用,应用软件从内核中读取 UNIX 时间。(匹配的clock_settime()系统调用允许他们步进,而adjtime()系统调用允许他们改变它。)

许多人对 POSIX 标准的规定提出非常明确和准确的要求。这些人通常没有真正阅读过 POSIX 标准。正如其基本原理所阐述的那样,标准使用的短语“自纪元以来的秒数”的计数故意没有指定 POSIX 秒与 SI 秒的长度相同,也没有指定结果gmtime()是“必然” UTC,尽管它出现了”。POSIX 标准是有意的足够宽松,以便它允许(比如)一个 UNIX 系统,管理员可以通过在闰秒调整发生后的一周重新设置时钟来手动修复闰秒调整。事实上,基本原理指出,它故意足够宽松,以适应那些故意将时钟设置为错误的系统,而不是当前 UTC 时间。

UTC 和 TAI

从内核获得的 UNIX 时间的解释取决于在应用程序中运行的库例程。POSIX 指定了内核时间和struct tm. 但是,正如丹尼尔·伯恩斯坦 (Daniel J. Bernstein) 曾经指出的那样,该标准的 1997 年版本令人尴尬地错误地弄错了公历的闰年规则(小学生学习的东西),因此从 2100 年开始计算就出错了。“违反比遵守更光荣”是一个很容易想到的短语。

确实如此。现在有几个系统基于 Arthur David Olson 编写的库例程进行这种解释,这些例程参考了臭名昭著的“奥尔森时区数据库”,通常编码在/usr/share/zoneinfo/. Olson 系统有两种模式:

  • 内核的“自纪元以来的秒数”被认为是计算自 1970-01-01 00:00:00 UTC 以来的 UTC 秒数,闰秒除外。这使用了一posix/组 Olson 时区数据库文件。每一天都有 86400 内核秒,一分钟内从来没有 61 秒,但它们并不总是 SI 秒的长度,内核时钟在闰秒发生时需要回转或步进。
  • 内核的“自 Epoch 以来的秒数”被认为是计算自 1970-01-01 00:00:10 TAI 以来的 TAI 秒数。这使用了一right/组 Olson 时区数据库文件。内核秒的长度为 1 SI 秒,内核时钟从不需要回转或步进来调整闰秒,但故障时间可以具有诸如 23:59:60 之类的值,而天数并不总是 86400 内核秒长。

M. Bernstein 编写了几个工具,包括他的daemontools工具集,right/因为他们只是添加了 10time_t来获得自 1970-01-01 00:00:00 TAI 以来的 TAI 秒数。他在手册页中记录了这一点。

这一要求(可能在不知不觉中)被 Felix von Leitner 的daemontools-encorerunit等工具集继承了libowfat。使用伯恩斯坦multilog冈特multilog,或佩普svlogd与奥尔森posix/结构中,例如,所有的TAI64N时间戳将(在写这篇的时间)的后面26秒实际TAI因为1970-01-01 00:00:10第二计数泰。

Laurent Bercot 和我在 s6 和 nosh 中解决了这个问题,尽管我们采取了不同的方法。M. Bercottai_from_sysclock()依赖于编译时标志。NOSH工具交易中TAI64N看看TZTZDIR环境变量来自动检测posix/right/如果他们能做到。

有趣的是,FreeBSD 文档time2posix()posix2time()函数允许等效于 Olsonright/模式与time_tTAI 秒。然而,它们显然没有被启用。

再来一次…

UNIX 时间是在运行 UNIX 的计算机上通过计算机硬件中包含的振荡器测量的。它不使用 SI 秒;它不是 UTC,即使它表面上看起来很像它;它故意让你的时钟出错。

进一步阅读