庚子年是中国传统的 60 甲子纪年法。擅长观测的古人很早就发现,每当年份执行到庚子这一年,自然灾害变多,突发事件频频,一些震动世界、影响安定的大事件也容易发生在这一年。而我们现在所处的 2020 年就是新一轮的庚子年,现在都 4 月了,很多网友都调侃说新的一年什么事情都没做,光在见证历史了。
当然了,作为一个技术博主,我并不是来给大家科普庚子年的,今天我们要说的是计算机中的一个比较危险的年份——2038 年。
frameLabelStart--frameLabelEnd
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 年。因此可能产生错误的计算及动作。就像下面这样。
所以如果时间将近 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 年问题那一天,估计全世界人已都在做同一件事情:
- 所有应用程序统统重新编写代码,至少得重新编译才能在新系统上运行
- 所有受影 2038 年影响的文件系统对应的分区,得统统格式化掉
- 在那天有的互联网服务都统统下线了,整个应用网络处于瘫痪状态
- 更离奇的是,你在银行的存款被清零了;对于那个贷款的家伙来说是个好事情,因为他们不用向银行还钱了
因此这样的做法无异于格式化整个世界,创建一个新的世界。我们当然不能这样。
不过,遗憾的是,当前并没有针对现有的 CPU/操作系统搭配的简单解决方案。直接将时间更改为 64 位模式将会破坏对于软件、数据存储以及所有与二进制表示时间相关的部分的二进位兼容性。更改成无符号的 32 位整数则会影响许多与两时间之差相关的程序。
那我们就真的无能为力了吗?并不是,我们还可以:
- 推广 64 位机器/软件的使用,争取当那一天来临的时候波及的设备尽可能少
- 做好对 32 位软件的兼容
不过大家也没必要恐慌,毕竟离 2038 年还有 18 年的时间,Linux 社区也开始着手处理这个问题了,离目标不远了,胜利在望。
最后
如果你真的有兴趣的话,可以到time.is/Unix这个网站,他会告诉你从 1970 年 1 月 1 日 0 点 0 分 0 秒开始到现在一共过了多少秒。
以上就是这次介绍的 2038 问题了,相信很多工程师都知道这个问题,也许到时候世界上就没有 32 位的机器了,或者是说已经有大佬解决了这个问题。毕竟已经有过千年虫问题的前车之鉴了,很多人已经知道要提前做准备了。
最后,如果你觉得我的文章对你有帮助的话,不妨给个关注支持一波,