上一篇文章说过,时间戳是从 1970 年开始累计的秒数。计算机用整数存它,而老式系统普遍用 32 位有符号整数——它能表示的最大值是 2147483647。把 2147483647 秒换算成日期,正好是 2038 年 1 月 19 日 03:14:07 UTC。

再过一秒,数字加一就会溢出,变成负数 -2147483648,对应的时间是 1901 年。也就是说,如果不处理,2038 年那个时刻之后,这些系统会突然觉得「现在是 1901 年」——文件时间错乱、证书显示过期、日志时间倒退,各种诡异问题。

它和 2000 年的「千年虫」是一类问题,但成因更底层:千年虫是年份只存了两位,2038 是整数的位数到头了。

好消息是,现代系统大多已经绕开:64 位系统的时间戳能撑到 2920 亿年后;JavaScript 的时间戳按毫秒存,是 64 位浮点,也远超这个范围;很多语言(如 Python 3、新版 PHP)默认用 64 位。真正有风险的是还在跑 32 位内核的嵌入式设备、老路由器、旧工业设备——它们可能永远不会被升级。

如果你在维护这类老系统,能做的检查很简单:确认操作系统是 64 位(uname -m 看架构),或者干脆把关键业务迁移出来。大部分普通用户其实不用做什么,但知道有这么回事,遇到「系统时间突然回到 1901 年」的怪事时能立刻对上号。

实用建议:新写的代码用时间戳时,尽量用平台自带的 64 位时间类型;别为了省内存手动用 32 位整数存秒数——省下来的那点空间不值得。