Unix 时间与 ISO 8601 写法
国际单位制之外的单位 · 量:以 1970 年起的整数秒表示的时刻
2038 年 1 月 19 日世界时三时十四分七秒,一个三十二位宽的秒计数器将走到 2 147 483 647 — 它所能容纳的最大数。下一次滴答会抬起最高位,同一个二进制字从此便被读作负数:凡以此计数保存时间的钟表,将不在 2038 年,而在 1901 年的十二月。这并非遥远未来的奇谈 — 一台工业控制器或一只水表,服役的年头长过所剩的十二年。
这套计数造得极简:秒自 1970 年 1 月 1 日子夜起接连而行,其中一日恒为 86 400 秒。正是这份简单,成了它两处特性的根源。一方面,由数字立刻可得历法日期,反之亦然,于是每一份事件日志、每一个数据库、每一套文件系统都以它记时。另一方面,闰秒在这样的计数中根本无从表达,也就是说,它名不副实,所编号的并非秒而是带小数的日,实为 UTC 写法的线性函数,而非流逝时间的计数器。
01 · 定义
Unix 时间是自 1970 年 1 月 1 日子夜协调世界时以来所经过的秒数,前提是每一日恰含 86 400 秒。ISO 8601 的写法以另一种方式陈述同一件事:以历法日期、当日时刻与相对本初子午线的偏移来表示,各字段严格自粗至细排列。
关于 86 400 秒的那一条保留,并非细枝末节,而是定义中最要紧之处。地球自转事务机构所宣告的闰秒,这套计数无从容纳,因此在插入的那一刻,系统要么把同一个数值重复两遍,要么把钟拨回。由此可得一件要紧的事:若两个事件之间落有一次插入,那么两个 unix 数之差便不是其间真正流逝的秒数 — 与原子时标的偏离已累积到二十七秒。
上限则不取决于定义,而取决于存储的位宽。三十二位带符号给出的最大值为 2 147 483 647,落在 2038 年 1 月 19 日;下一次增量把最高位置为一,使数变负,将钟抛回 1901 年 12 月 13 日。六十四位把这道界线向前推了两千九百二十亿年,然而同样是这六十四位,其中的整数纳秒早在 2262 年便已耗尽。
依标准的写法要解决的是另一桩事 — 交换而非存储 — 故而其中要紧的,是数字全然没有的那些东西:时区偏移、日期与时刻之间的分隔符,以及字符串等长时字典序与时间序相合这一条规则。正是这最后一项性质,使这一格式成了文件名与日志中排序的根基。
请以滑块牵引时间,看寄存器如何填满:各位自右向左点亮,只要最高的那一位、符号位仍旧暗着,数便是正的,日期便在增长。计数器一旦越过 2 147 483 647,最高位就红光骤起,整个数变负,钟跳回 1901 年。
绿色的直线是原子时标,那里每一秒确实是一秒。红色的阶梯线是 Unix 时间,每逢插入便把同一个时间戳给出两回,因而线在原地停住。偏离已达二十七秒且仍在增长,故而这套计数用于历法日期尚可,用于物理学中量度时段则不可。
02 · 换算
请输入时间戳或日期
计数的各倍数之间 — 秒、毫秒、微秒与纳秒 — 换算是精确的,因为彼此只差一个因子。近似的只有一行:换算到原子时标,须知道截至所给时刻已累积了多少闰秒。
依标准解析字符串,本页在带 Z 的扩展写法中进行;不带分隔符的基本形式已移入精细设置。
2038 年的问题不在标准,而在硬件与旧代码之中:三十二位的时间戳坐在各类仪表的固件里、工业控制器里、文件系统的格式里,以及那些字段早已声明为四字节的数据库里。在源码中改动类型不难;难的是在所剩的十二年里逐一走过数以百万计已装设的器件 — 这与 2000 年之前所面对的,是同一类的活计。
| 数值 | 说明 | ||
|---|---|---|---|
| {u} | {name} | {value} | {note} |
03 · 数量级
对数标度:自一秒至六十四位的上限04 · 测量仪器
以何物为事件盖上时间戳
另有一枚带电池的芯片,在器件断电时仍维持计数。它通常保存的并非 unix 时间戳,而是分开存放的历法各字段,其年份字段的位宽自有其数,因此在老旧电路板上,关于 2038 的谈话往往从这一问起头:芯片本身能数到哪一年。
NTP 协议把机器的钟对到共同时间,精度可达数毫秒,它同时也以专门的标志在一日之前预告插入。它自己也有一道界线,且来得更早:计数自 1900 年起,用的是无符号三十二位,将在 2036 年二月溢出。
写入日志的时间戳,或用数字,或用依标准的字符串,而后者更可取,理由恰只有一条:等长的字符串,字典序与时间序相合,于是各条记录无须解析日期便能排好。正因如此,这一格式远远越出了计算技术的范围而流布开来。
要试一台器件对 2038 年是否有备,只有一个法子 — 把它的钟拨过那道不祥的界线,看日志、证书与区间计算会成什么样子。人们已借此在计费、门禁系统与密钥有效期中找出了故障:那里未来的日期是由加法得出的,远在界线本身之前就已溢出。
05 · 书写规则
自粗至细,且始终带时区偏移
标准要求各字段依递减次序排列、年份四位、以连字符作日期分隔、时刻之前冠以字母 T;时区偏移或以字母 Z 表示本初子午线,或写作正负时与分。unix 时间戳写作整数,不分节,且必须注明倍数,因为一千的因子把秒与毫秒分开,而单看数的大小,两者极易相混。
第一种写法在不同国家读法不一,故而在数据交换中不可取。第二种把分隔符与偏移一并略去,于是时刻在两个方向上各有一日的不确定。第三种丢掉了前导零,字符串便不再按字典序排列 — 而这一格式所受的看重,恰恰正在此性质。第四种在 unix 计数与原子时标之间画上等号,可两者之间横着二十七秒累积的插入。
06 · 相邻单位
与之并列的,是所有依同一原理造成、只是起点不同的计数:NTP 时间自 1900 年起,儒略日自公元前 4713 年正午起,卫星系统的时标自 1980 年一月起。它们只在纪元与单位上有别,故而减去一个常数即可换算。
有符号的秒
其上限已落在 2036 年
闰秒如实计入
在 Simetrium 的档案中 与之相邻的是 儒略日,换算常数即取自于此, UTC、TAI 与 UT1 各时标,用以解释消失的闰秒, 秒 作为计数的单位,以及 比特,其位宽正决定了上限。
07 · 历史部分
因比特不足而择定的纪元
在第一部 Unix 手册中,时间自 1971 年初起,以秒的六十分之一计数,三十二位中这样的计数仅能容下两年上下。它耗尽得如此之快,以致每出一版系统就得挪一次纪元,于是舍去秒的分数,改用整秒。
改用整秒之后,开发者赢得了一百三十六年的余量,遂能依便利而非依无奈来择定起点。取的是 1970 年 1 月 1 日 — 过去最近的一个整年之始,机器记录本来也到不了那里 — 自此再未改动过一次,尽管系统曾不止一次从根本上重写。
国际标准化组织把各自分道的国别格式归并为一,并以一条简单的规则为其根基:各字段自粗至细,皆带前导零。这一副产品竟比初衷更为要紧 — 这样的字符串可如数字般排序,于是格式流入了文件名、日志与各种交换协议。
桌面与服务器系统早已转到六十四位,那里的界线被推到了任何合乎情理的视野之外。危险留在了别处:留在服役二十年的仪器固件里,留在字段声明为四字节的文件格式里,也留在对将来期限的计算里 — 只消在今日的日期上加十五年,今天就已溢出。
一种名不副实、并不计秒的计数
Unix 时间的定义听来像是在计秒,然而每日整整 86 400 秒这一要求,使它成了别的东西:UTC 写法的线性函数,而非流逝时间的量度。每当地球自转事务机构宣告一次插入,这套计数便须把同一个数值重复两遍,或者向后一跳,而两个时间戳之差恰恰失掉了那一秒。半个世纪里,这样的损失累计已有二十七次,故而凡需真正时段的活计,取的是原子时标,而非此者。
第二处特性全然不在定义之中,而在存储的方式之中,这也使它成为我们这份目录里唯一一道既非自然、亦非约定所设,而是由机器字长所设的上限。儒略日永无尽期,因为它是个数;Unix 时间在 2038 年 1 月 19 日走到尽头,因为它是个四字节的字段。量与其表示之间的分别,向来不大牵动计量学家的心思,而在此处,恰恰正是它决定了一切。
目录 · 计量单位
每个量都有一份档案
七个 SI 基本单位,二十二个有专名的导出单位,以及若干制外量 — 少了它们,工程与历法都转不动。