关于各种时间标准

关于各种时间标准(时间系统)

编程中, 许多的定时任务都与”标准时间”有关, 程序中对时间处理不当可能导致难以排查的问题, 甚至在金融, 通信, 电力, 交通等行业中引起重大bug, 产生巨大危害. 作为程序员, 应当对时间表示的方法有所了解, 明白各种时间表示的区别及可能导致程序bug的特殊时间点.

0x00 在阅读之前

本文接下来的所有内容遵循以下规约:

  • 所有的时间将被用 yyyy-mm-dd hh:mm:ss(zzz) 的形式严格表达.
  • 未被严格表示的时间都默认为协调世界时(UTC).
  • 未经特殊表达的秒的定义均遵循国际单位制1967年的原子秒定义.

0x01 常见标准时间

格林尼治标准时间(GMT)

通常世界时(UT)也指代GMT
本初子午线被定义在通过格林尼治的经线, 理论上来说, 格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时的时间. 由于地球在它的椭圆轨道里的运动速度不均匀, 这个时刻可能和实际的太阳时相差16分钟. 自1924年2月5日开始, 格林尼治天文台每隔一小时会向全世界发放调时信息. 1960年以前, GMT曾作为基本时间计量系统被广泛应用. 由于地球自转速度变化的影响, 它不是一种均匀的时间系统. 但是, 因为它与地球自转的角度有关, 所以即使在1960年作为时间计量标准的职能被历书时(ET)取代以后, 世界时对于日常生活,天文导航,大地测量和宇宙飞行器跟踪等仍是必需的. 同时, 精确的世界时是地球自转的基本数据之一, 可以为地球自转理论,地球内部结构,板块运动,地震预报以及地球,地月系,太阳系起源和演化等有关学科的研究提供必要的基本资料.

历书时(ET)

它是由天体力学的定律确定的均匀时间﹐又称牛顿时. 由于地球自转的不均匀性﹐1958年国际天文学联合会决议﹐自1960年开始用历书时代替世界时作为基本的时间计量系统﹐并规定世界各国天文年历的太阳,月球,行星历表﹐都以历书时为准进行计算.

国际原子时(TAI)

原子时计量的基本单位是原子时秒. 它的定义是: 铯原子基态的两个超精细能级间在零磁场下跃迁辐射9,192,631,770周所持续的时间. 1967年第十三届国际计量大会决定, 把在海平面实现的上述原子时秒, 规定为国际单位制中的时间单位.
根据原子时秒的定义, 任何原子钟在确定起始历元后, 都可以提供原子时. 由各实验室用足够精确的铯原子钟导出的原子时称为地方原子时. 目前, 全世界大约有20多个国家的不同实验室分别建立了各自独立的地方原子时. 国际时间局比较,综合全球范围240台原子钟数据, 最后确定的原子时, 称为国际原子时, 简称TAI.
TAI起点定在1958年1月1日0时0分0秒(UT), 即规定在这一瞬间原子时时刻与世界时刻重合. 但事后发现, 在该瞬间原子时与世界时的时刻之差为0.0039秒. 这一差值就作为历史事实而保留下来. 在确定原子时起点之后, 由于地球自转速度不均匀, 世界时与原子时之间的时差便逐年积累.

协调世界时(UTC)

协调世界时是以原子时秒长为基础, 在时刻上尽量接近于世界时的一种时间计量系统. 这是日常编程工作中最常接触使用的时间标准.
世界时的时间计量系统是基于地球自转时间. 太阳的东升西落是长期以来人们计算时间的主要依据, 太阳走到天空中最正中的位置时, 就是12时. 在世界时(UT)的计量系统中, 一秒有多长, 取决于一天(地球自转一周的时间)有多长, 但地球的自转速度并不是恒定的, 地球自转时快时慢, 则一秒的定义也随之浮动, 这无疑会给精密计量场合带来困扰, 而原子时准确稳固定义了一秒的长度, 由此则导致了上文TAI的介绍中提到的世界时与原子时之间逐年积累的时差, 若不将原子时加以修正, 根据国际计量局测算, 约5000年后原子时将和世界时差1小时, 也即是5000年后正午太阳将在13:00 直射地球, 且这个偏移还将继续堆积.为了应对这种情况, 协调世界时的折衷时标于1972年面世. 为确保协调世界时与世界时相差不会超过0.9秒, 在有需要的情况下会在协调世界时内加上正或负闰秒. 因此协调世界时与国际原子时之间会出现若干整数秒的差别, 两者之差逐年积累, 采用闰秒的方法使协调时与世界时的时刻相接近, 两者偏差不超过0.9s. 它保持时间尺度的均匀性(但破坏了时间的连续性), 近似地反映地球自转的变化. 按国际无线电咨询委员会(CCIR)通过的关于UTC的修正案, 从1972年1月1日起UTC与UT之间的差值最大可以达到±0.9s. 位于巴黎的国际地球自转事务中央局负责决定何时加入闰秒. 一般会在每年的6月30日,12月31日的最后一秒进行调整. 这套时间系统被应用于许多互联网的标准中.

GPS时(GPST)

GPS时(GPST)是由GPS星载原子钟和地面监控站原子钟组成的一种原子时基准, 与国际原子时(TAI)保持有19s的常数差, 并在GPS标准历元1980年1月6日零时与UTC保持一致. CPS时间在0~604800s之间变化, 0s是每星期六午夜且每到此时GPS时间重新设定为0s, GPS周数加1. 为了保持系统定位,导航,授时的连续性, GPS时不引入闰秒. 实际上GPS的时和协调世界时有一个公式, 因为这两个时间系统在1980年1月6日0时是一致的, 而UTC时存在闰秒, 因而一段时间后, 两种时间系统会相差n个整秒. (n为这段时间内UTC积累的闰秒数)当前最近一次闰秒的时间点为2017-01-01(UTC), 换算公式为GPS = UTC + 18s.

关于GPS周:

当GPS时间记录满604800s时, GPS周数+1. GPS周数起始于 1980-01-06 00:00(UTC), GPS周数范围为0到1023, 超过上限以后将回滚为0, 然后继续循环计数. 因此一个GPS循环=1024周=7168天=19.62年, 目前为止仅有的一次周数回滚发生在1999-08-22 00:00(GPST).

0x02 关于闰秒(leap second)

闰秒的目的是为了在保持通用的时间标准于人类起居时间概念在较长时间尺度内的统一, 但对于授时机构,通信,航天,电子等时间精度要求较高的领域而言需要时间保持连续性. 全球卫星导航精确到纳秒, 而卫星发射需要精确到微秒以上. 闰秒的出现, 起到弥补和修正的作用, 但客观上导致了时间的中断. 目前, 全球已经进行了27次闰秒, 均为正闰秒. 最近一次闰秒在 2017-01-01 00:59:59(UTC) 出现. 这也是本世纪的第五次闰秒.

置闰细节:

增加正闰秒时, 这一秒是增加在第二天的00:00:00之前, 效果是延缓UTC第二天的开始. 当天23:59:59的下一秒被记为23:59:60, 然后才是第二天的00:00:00.
如果是负闰秒的话, 23:59:58的下一秒就是第二天的00:00:00了, 但目前还没有负闰秒调整的需求.

闰秒对程序造成的影响

以下内容援引自新闻媒体报道:

据国外媒体报道, 上周日晚Reddit,Mozilla和Gawker等多家网站遭遇短暂的技术故障, 原因在于在将”闰秒”加入世界原子钟的过程中, 支撑这些网站操作的软件受到影响.

上周六, 格林威治时间午夜, 从6月跨越到7月的过程中, 地球官方时间将回拨一秒, 以保持和地球每日自转同步. 根据网上的多篇报道, 包括Liunx操作系统和Java应用平台在内的多个软件基础平台无法处理这多出来的一秒.

新闻聚合和讨论网站Reddit就遭遇”Java/Cassandra”问题. Java/Cassandra”是Facebook用Java开发的开源数据库. 不过Reddit没有回应关于此事的置评要求.

与此同时, Mozilla网站稳定性工程师, 同时又是火狐浏览器开发者的Eric Ziegenhorn发布了一份bug报告, 称Mozilla正遭遇Hadoop问题. Hadoop是另一个用Java开发的开源平台. 自从午夜出现问题之后, Ziegenhorn 同样将这一问题归咎于闰秒.

其他人则抱怨Linux服务器出现问题. 根据BuzzFeed的报道, Foursquare,Yelp,LinkedIn,Gawker和StumbleUpon同样受到闰秒bug的困扰. 这5家网站中只有Gawker回应了置评要求, 声称它因为使用了Tomcat网络服务器架设自己的网站而遭遇”闰秒”问题.

去年9月, 谷歌在一篇帖子中详细阐述了如何处理闰秒问题. 这家网络巨头使用了一种叫做”闰秒弥补”的技术, 也就是在官方闰秒到来之前, 逐步在自己的系统时钟中增加毫秒.

谷歌表示, 这意味着当时间在午夜新增一秒, 公司的时钟已经考虑到了这一点, 并通过偏移时间的方法来解决. 公司所有服务器可以继续正常提供服务, 而根本不用顾及”闰秒”问题.

历史闰秒统计表:

0x03 关于时间戳(timestamp)

时间戳也是编程工作中接触频率很高的时间表示法. 一般的时间戳指代Unix 时间戳(或称POSIX时间), 是一个用于描述时间点的系统, 时间戳的数值等于1970-01-01 00:00:00(UTC) 起至现在的总秒数减去经历的闰秒数. 由于时间戳数值中并不包含闰秒数, 故在于UTC时间的换算中可把所有时间都按一分钟60秒计算, 无须考虑一分钟61秒的闰秒情况.(另在收集资料的过程中, 发现百度百科对时间戳的定义有误, 百科中介绍起始时间为格林威治时间1970-01-01- 00:00:00(GMT), 实际应为UTC时间.) 由于时间戳为相对时间, 故不存在时区区别, 本文写作时间 2019-02-23 16:07:24(UTC) 全时区的时间戳都为1550938044

时间戳如何处理闰秒

以1998年12月闰秒为例, 展示时间戳对闰秒的处理细节:

2038年问题

在 2038-01-19 03:14:07(UTC) 这一时刻, 时间戳将耗尽32bit所能表达的最大秒数, 超过此一瞬间, 时间将会被掩盖(wrap around)且在内部被表示为一个负数, 并造成程序无法工作, 因为它们无法将此时间识别为2038年, 而可能会依个别实作而跳回1970年或1901 年. 错误的计算及动作可能因此产生, 被称为2038年问题.

0x04 资料附录

TimeAndDate

GPSclock

Timescales