庚子年是中国传统的 60 甲子纪年法。擅长观测的古人很早就发现,每当年份执行到庚子这一年,自然灾害变多,突发事件频频,一些震动世界、影响安定的大事件也容易发生在这一年。而我们现在所处的 2020 年就是新一轮的庚子年,现在都 4 月了,很多网友都调侃说新的一年什么事情都没做,光在见证历史了。

当然了,作为一个技术博主,我并不是来给大家科普庚子年的,今天我们要说的是计算机中的一个比较危险的年份——2038 年。

2038 年问题

在说 2038 年问题前,我们需要先明白计算机是如何存储系统时间的。

在 Unix 或类 Unix 系统中,都是以 1970 年 1 月 1 日 0 点 0 分 0 秒作为时间的基准点,用秒数来表示系统时间,也即当前系统时间是从基准时间(1970 年 1 月 1 日 0 点 0 分 0 秒)走过多少秒之后的时间。

用公式简单表示就是这样:系统时间 = 基准时间 + 秒数

因为基准时间是确定的,所以我们唯一需要考虑的就是秒数应该如何保存。在当时那个年代,计算机硬件资源非常紧缺,用 16 位表示数据就已经是一个非常奢侈的选择了。因此当时的设计者都认为用 32 位存储秒数已经**“足够大”**了。所以从那个时候开始使用 32 位来表示秒数。

我们知道在二进制中,32 位数能表示的最大的数是$2^{32}-1$,不过为了能够让时间可以往前往后数,会用第一位作为正负的判断位,第一位如果为 0,则说明为正;若第一位是 1,则说明为负。因此,在 Unix 或类 Unix 系统中,这$2^{32}-1$个数被分成了 2 部分,分别是$+2^{31}-1$和$-2^{31}$。这样我们就可以以 1970 年 1 月 1 日 0 点 0 分 0 秒作为时间的基准点,往前往后每过一秒就加一个数字,依此来计算时间。

这个时间的最后结束点是 2038 年 1 月 19 日 03:14:07,一旦越过这个瞬间,时间将会“绕回”(wrap around)且在内部被表示为一个负数,并造成程序无法工作,因为它们无法将此时间识别为 2038 年,而可能会依个别实现而跳回 1970 年或 1901 年。因此可能产生错误的计算及动作。就像下面这样。

img

所以如果时间将近 2038 年时,还存在 32 位机器在世界中运行,那将会受到 2038 年问题的影响。

从这也可以看出为什么很多厂商都不再提供 32 位支持了。

危害性

可能很多人都疑惑,这不就是个时间问题吗?有你说的那么严重吗?

当然,简单来看这就是个时间问题,而且换成 64 位的机器 2038 年问题就会自动消失了。但这只是一厢情愿,对于嵌入式设备来说,现在还有大量 32 位系统在全球各地运行,谁也无法保证这些系统在 2038 年之前就能光荣退役。

而且很多程序都会依托时间进行计算,最简单的就是银行的贷款利息等金融服务的计算,如果不解决,就一定会出现各种混乱。

而且,由于这个特殊时间点的存在,并不是说只有到 2038 年的时候才会出现问题,比如前两年就出现过,将 iPhone/iPad 等设备日期设置成 1970 年 1 月 1 日,设备就会变砖,并且无法通过寻常的备份还原等手段进行恢复。就是因为,iOS 是基于 Unix 操作系统构建的。

而且事实上 2038 年问题的范围远不止于此。前面谈到的问题都还是操作系统运行时表示数据的溢出,但还有一些数据是静静在躺在某个磁盘上,当时间走到 2038 之后再把它它们翻读出来,一样会出现问题。

我们知道文件都有几种时间属性,比如创建时间,最后一次访问时间,最后一次修改时间。如果该时间类型也是 32 位有符号数,那在 2038 之后的某个早晨,试想一下你和朋友喝着咖啡,回忆起 2038 年以前的某次旅游,你兴高采烈说着之前见闻,并拿出手提电脑打开之前拍下的照片,这时扫兴的事情将会发生,文件打不出或者出错。

所以说,如果这个问题不解决,夸张点说,未来真的可能会出现,全世界大部分的电子设备全部瘫痪的场景。

如何解决

2038 年问题的根源就是使用了 32 位有符号整数来表示时间,看起来它的解决方案非常的简单,直接粗暴地将32 位有符号整数 修改成 64 位有符号整数

如果真的这样做,那对这个世界会产生什么影响呢? 在修复 2038 年问题那一天,估计全世界人已都在做同一件事情:

  1. 所有应用程序统统重新编写代码,至少得重新编译才能在新系统上运行
  2. 所有受影 2038 年影响的文件系统对应的分区,得统统格式化掉
  3. 在那天有的互联网服务都统统下线了,整个应用网络处于瘫痪状态
  4. 更离奇的是,你在银行的存款被清零了;对于那个贷款的家伙来说是个好事情,因为他们不用向银行还钱了

因此这样的做法无异于格式化整个世界,创建一个新的世界。我们当然不能这样。

不过,遗憾的是,当前并没有针对现有的 CPU/操作系统搭配的简单解决方案。直接将时间更改为 64 位模式将会破坏对于软件、数据存储以及所有与二进制表示时间相关的部分的二进位兼容性。更改成无符号的 32 位整数则会影响许多与两时间之差相关的程序。

那我们就真的无能为力了吗?并不是,我们还可以:

  1. 推广 64 位机器/软件的使用,争取当那一天来临的时候波及的设备尽可能少
  2. 做好对 32 位软件的兼容

不过大家也没必要恐慌,毕竟离 2038 年还有 18 年的时间,Linux 社区也开始着手处理这个问题了,离目标不远了,胜利在望。

最后

如果你真的有兴趣的话,可以到time.is/Unix这个网站,他会告诉你从 1970 年 1 月 1 日 0 点 0 分 0 秒开始到现在一共过了多少秒。

以上就是这次介绍的 2038 问题了,相信很多工程师都知道这个问题,也许到时候世界上就没有 32 位的机器了,或者是说已经有大佬解决了这个问题。毕竟已经有过千年虫问题的前车之鉴了,很多人已经知道要提前做准备了。

最后,如果你觉得我的文章对你有帮助的话,不妨给个关注支持一波,