今天在写 new Date() 时候,无意中发现了一个很有意思的方法,getTime(),百度了一下,有人说是计算从 1970 年 1 月 1 日至今的毫秒数

为什么要是 1970 年呢?

new Date().getTime();

// xxxxxxxxxxx

这个起源于 unix 的诞生,因为 Unix 在 1969 年被开发出来,1971 年正式发布,在这之前没有机器会需要来表示 1970-01-01-00:00:00 之前的时间,后面的语言很多就沿用了这一习惯,js 只是也沿用了这种习惯而已。

当然,这一做法现在看来是很有问题的,例如不方便用它表示更早的时间而且精度有限。

定义 time 从 1970 年 1 月 1 日开始,忽然想到在 JAVA 里,Oracle 数据库时间也是从 1970 年 1 月 1 日开始计算。

比如 java 类代码:

Date date = new Date(0);

System.out.println(date);

// 打印出来的结果:Thu Jan 01 08:00:00 CST 1970也

是 1970 年 1 月 1 日,实际上时分秒是 0 点 0 分 0 秒 (这里打印出来是 8 点,稍后会作解释)。

为什么这个时间会定义在 1970 年 1 月 1 日这个时候呢?

于是开始了 Google,中文网页根本找不到答案。于是试着搜索英文关键字,在 Sun java 论坛总算找到准确的帖子:

http://forums.sun.com/thread.jspa?threadID=595140&start=15

其中有一个回复:

I suspect that Java was born and raised on a UNIX system. UNIX considers the epoch (when did time begin) to be midnight, January 1, 1970. 是说 java 起源于 UNIX 系统,而 UNIX 认为 1970 年 1 月 1 日 0 点是时间纪元。

但这依然没很好的解释"为什么",出于好奇,继续 Google,总算找到了答案:

http://en.wikipedia.org/wiki/Unix_time

这里的解释是:

最初计算机操作系统是 32 位,而时间也是用 32 位表示。

System.out.println(Integer.MAX_VALUE);

2147483647

Integer 在 JAVA 内用 32 位表示,因此 32 位能表示的最大值是 2147483647。另外 1 年 365 天的总秒数是 31536000,2147483647/31536000 = 68.1,也就是说 32 位能表示的最长时间是 68 年,而实际上到 2038 年 01 月 19 日 03 时 14 分 07 秒,便会到达最大时间,过了这个时间点,所有 32 位操作系统时间便会变为 10000000 00000000 00000000 00000000 也就是 1901 年 12 月 13 日 20 时 45 分 52 秒,这样便会出现时间回归的现象,很多软件便会运行异常了。

到这里,我想问题的答案已经出来了:

因为用 32 位来表示时间的最大间隔是 68 年,而最早出现的 UNIX 操作系统考虑到计算机产生的年代和应用的时限综合取了 1970 年 1 月 1 日作为 UNIX TIME 的纪元时间 (开始时间),而 java 自然也遵循了这一约束。

至于时间回归的现象相信随着 64 为操作系统的产生逐渐得到解决,因为用 64 位操作系统可以表示到 292,277,026,596 年 12 月 4 日 15 时 30 分 08 秒,相信我们的 N 代子孙,哪怕地球毁灭那天都不用愁不够用了,因为这个时间已经是千亿年以后了。

最后一个问题:

上面 System.out.println(new Date(0)),打印出来的时间是 8 点而非 0 点,原因是存在系统时间和本地时间的问题,其实系统时间依然是 0 点,只不过我的电脑时区设置为东 8 区,故打印的结果是 8 点。