author:onceday date:2022年6月3日
在现有的世界时间体系中,存在多种标准,然而用得最多的就是世界时和原子时了。世界时是根据地球自转为准的时间尺度,然而由于多种因素影响,因此地球自转并不稳定,导致世界时也不是均匀的时间尺度。 以原子震荡周期为基础,并由世界度量衡局以世界各国家实验室原子钟群加权平均产生之时间尺度称为国际原子时。原子时相对世界时稳定,因此经过一段时间以后,国际原子时与世界时渐渐产生了不一致。为了 使生活中之自然时刻能与原子时相符合,国际另外从国际原子时(TAI)引出一计时方式,称为协调世界时(UTC),作为最终之国际时刻标准。
此方式早期采用原子频率偏调,到公元一九七二年七月一日首次改用闰秒调整,当世界协调时(UTC)与一号世界时(UT1)之差(Difference UT1, DUT1)的绝对值预期在半年或一年之内将超过0.9秒时,为保持DUT1在0.9秒内,国际地球自转组织(International Earth Rotation Service, IERS)便会发布闰秒通告。在当年12月31日或6月30日的最后一分钟(UTC时间,换算北京时间为次年1月1日上午7时59分或7月1日上午7时59分)做闰秒调整。增加一秒时为正闰秒,减少为负闰秒。如果这一秒是被加载第二天的00:00:00前,则当决定加入正闰秒时,当天23:59:59的下一秒当记为23:59:60,然后才是第二天的00:00:00。如果是负闰秒,23:59:58的下一秒就是第二天的00:00:00了。
值得注意的是原子时(TAI)与世界时(UT1)分别来自于两个互不相干的系统,虽然 协调时(UTC)基本上解决了两者之间的协调问题,但是由于地球自转速度越来越慢加之不均匀,按照目前情况,不能排除若干年后出现一年闰几次甚至更多次秒 的可能性。因此IERS发布闰秒公告的时间也是不定的。
参考文档:
Unix 时间数字在 Unix 纪元时为零,并且自纪元以来每天增加 86400。所以它不能代表闰秒。 操作系统将减慢时钟以适应这种情况。 就 Unix 时间戳而言,闰秒根本不存在。
如何理解呢?
对于Unix的时间戳来说,每天的时间秒数是固定的,即60x60x24=86400s,这意味着每秒的时间长度不是固定的。
再来看一看真正准确的每秒时间是如何来的,即物理学意义上的精准时间单位!
GMT 和 UT1 基于地球在宇宙中的天文位置。 TAI 基于通过物理(原子)反应测量的在宇宙中经过的实际时间量。 在 TAI 中,每一秒都是一个“SI 秒”,它们的长度完全相同。 在 UTC 中,每一秒都是 SI 秒,但必要时会添加闰秒以将时钟重新调整回 GMT/UT1 的 0.9 秒以内。 GMT 和 UT1 时间标准是由地球在宇宙中的位置和运动的经验测量定义的,这些经验测量不能通过任何方式(无论是科学理论还是近似)来预测。 因此,闰秒也是不可预测的。
很明显,Unix时间戳是与它们截然不同的,在有闰秒的日子里,午夜前的第二秒(午夜前 UTC 分钟的第 61 秒)被赋予与前一秒相同的时间戳。用直接的方式来看,其相同的 Unix 时间戳将用于两个真实世界的秒数。
X86399.0
、 X86399.5
、 X86400.0
、 X86400.5
、 X86400.0
、 X86400.5
、 X86401.0
。
如上所示,时间戳将被“重播”,闰秒时间戳也是前一个真实世界秒的时间戳。
向标准库添加对闰秒的支持非常困难,因为无法预测未来的闰秒次数,因此日期2050 年 1 月 1 日无法存储为UTC时间戳,因为 IAU 不知道在接下来的几十年中我们必须添加多少闰秒。
而Unix时间非常简单,因为每年每天的时间戳是固定的。直接计算就可以了。
简而言之:UTC 全年都非常难以使用,而 Unix 时间仅在闰秒发生的瞬间才难以使用。
>>> time.strptime("2017-1-1 7:59:60","%Y-%m-%d %H:%M:%S")
time.struct_time(tm_year=2017, tm_mon=1, tm_mday=1, tm_hour=7, tm_min=59, tm_sec=60, tm_wday=6, tm_yday=1, tm_isdst=-1)
>>> a=time.mktime(_)
>>> time.localtime(a)
time.struct_time(tm_year=2017, tm_mon=1, tm_mday=1, tm_hour=8, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=1, tm_isdst=0)
>>> time.localtime(a-1)
time.struct_time(tm_year=2017, tm_mon=1, tm_mday=1, tm_hour=7, tm_min=59, tm_sec=59, tm_wday=6, tm_yday=1, tm_isdst=0)
>>>
2017年1月1日,北京时间7:59:60是一个闰秒,所以这一时刻存在60秒这个值,但在Unix时间戳里面可以看到,它实际等于8:00:00,意味着同一个时间戳对应了两个真实时间。
因此,在计时的时候,如果硬件定时器计时的时长和Unix时间戳出现了差距,很正常,不是说很小的精度误差,而是指来自于这类闰秒。
因此,可以说Unix时间戳确实可以计算出当前的日期时间出来,但是日期的具体一天或者一个小时,或者直接点说,其中1秒,其时间长度并不真正意义上等于物理1秒,但在绝大数情况等于。
在没有网络校准时间时,如果经过了闰秒,大概率unix时间会快1秒(或者慢),因为计算机内部计时器误差还是很小的,能较准确的计算出当天走过的秒数。但是,一旦通过网络校准了 时间,就会去掉多出的一秒。
所以说,Unix时间戳每天的时间秒数是固定的,即60x60x24=86400s。