The epoch is the point where the time starts. On January 1st of that year, at 0 hours,the “time since the epoch” is zero. For Unix, the epoch is 1970. To find out what the epoch is, look at gmtime(0).
定义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点。
我想以上问题如果作为面试题,也能难倒一批人了.
现在计算机和一些电子设备时间的计算和显示是以距历元(即格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000,格里高利历)的偏移量为标准的,如1970-1-10 20:47 偏移量为2724441632毫秒,出现类似字样说明时间被初始化了。
小知识:
格林威治标准时间GMT
许多人都知道两地时间表简称为GMT或UTC,而世界时区表则通称为World Time
,那么GMT与UTC的实质原意又是为何?世界时区又是怎么区分的?面盘上密密麻麻
的英文单字代表着什么意义与作用呢?这些都是新手在接触两地时间表或世界时区表
时,脑海中所不断浮现的种种疑问,以下将带您一探时区奥妙的究竟。
全球24个时区的划分
相较于两地时间表,可以显示世界各时区时间和地名的世界时区表(World Time)
,就显得精密与复杂多了,通常世界时区表的表盘上会标示着全球24个时区的城市名
称,但究竟这24个时区是如何产生的?过去世界各地原本各自订定当地时间,但随着
交通和电讯的发达,各地交流日益频繁,不同的地方时间,造成许多困扰,于是在西
元1884年的国际会议上制定了全球性的标准时,明定以英国伦敦格林威治这个地方为
零度经线的起点(亦称为本初子午线),并以地球由西向东每24小时自转一周360°
,订定每隔经度15°,时差1小时。而每15°的经线则称为该时区的中央经线,将全球划
分为24个时区,其中包含23个整时区及180°经线左右两侧的2个半时区。
就全球的时间来看,东经的时间比西经要早,也就是如果格林威治时间是中午12时,
则中央经线15°E的时区为下午1时,中央经线30°E时区的时间为下午2时;反之,中央
经线15°W的时区时间为上午11时,中央经线30°W时区的时间为上午10时。以台湾
为例,台湾位于东经121°,换算后与格林威治就有8小时的时差。如果两人同时从格
林威治的0°各往东、西方前进,当他们在经线180°时,就会相差24小时,所以经线180°
被定为国际换日线,由西向东通过此线时日期要减去一日,反之,若由东向西则要增 ,
加一日。
十七世纪,格林威治皇家天文台为了海上霸权的扩张计画而进行天体观测。1675年旧
皇家观测所(Old Royal Observatory) 正式成立,到了1884年决定以通过格林威治
的子午线作为划分地球东西两半球的经度零度。观测所门口墙上有一个标志24小时的
时钟,显示当下的时间,对全球而言,这里所设定的时间是世界时间参考点,全球都
以格林威治的时间作为标准来设定时间,这就是我们耳熟能详的「格林威治标准时间
(Greenwich Mean Time,简称G.M.T.)的由来,标示在手表上,则代表此表具有
两地时间功能,也就是同时可以显示原居地和另一个国度的时间.
世界协调时间UTC
多数的两地时间表都以GMT来表示,但也有些两地时间表上看不到GMT字样,出现的
反而是UTC这3个英文字母,究竟何谓UTC?事实上,UTC指的是Coordinated Universal
世界协调时间(又称世界标准时间、世界统一时间),是经过平均太阳时(以格
林威治时间GMT为准)、地轴运动修正后的新时标以及以「秒」为单位的国际原子时所
综合精算而成的时间,计算过程相当严谨精密,因此若以「世界标准时间」的角度来
说,UTC比GMT来得更加精准。其误差值必须保持在0.9秒以内,若大于0.9秒则由位
于巴黎的国际地球自转事务中央局发布闰秒,使UTC与地球自转周期一致。所以基本
上UTC的本质强调的是比GMT更为精确的世界时间标准,不过对于现行表款来说,
GMT与UTC的功能与精确度是没有差别的
从1884年起,格林威治标准时间为其他国家所承认。无怪
现在人们都把英国的格林威治天文台说成是“时间开始的地方”呢。
而为什么现代计算机(电话,电子设备)时间以1970 年 1 月 1 日的 00:00:00.000为基准呢,这是Unix**, 是以Unix诞生的时间为参照确定的。
扩展知识:
Unix时间并没有出现错误
1234567890是个节日, 一秒钟的节日. 它不是问题, 不是错误, 不是BUG. 我们人类使用的计时系统是相当复杂的:秒是基本单位, 60秒为1分钟, 60分钟为1小时, 24小时是一天......如果计算机也使用相同的方式来计时, 那显然就要用多个变量来分别存放年月日时分秒, 不停的进行进位运算, 而且还要处理偶尔的闰年和闰秒以及协调不同的时区. 基于"追求简单"的设计理念, UNIX在内部采用了一种最简单的计时方式:
计算从UNIX诞生[注释1]的UTC时间1970年1月1日0时0分0秒起, 流逝的秒数. UTC时间1970年1月1日0时0分0秒就是UNIX时间0, UTC时间1970年1月2日0时0分0秒就是UNIX时间86400. 这个计时系统被所有的UNIX和UNIX-like系统继承了下来, 而且影响了许多非UNIX系统. POSIX标准推出后, 这个时间也被称为POSIX时间.
UNIX时间错误是误解
可能是因为人类是一种需要精神上的刺激的生物吧, 各种历法中都存在着各种拥有不同意义的节日. 其中, 很多节日仅仅由于日期的特殊性就被赋予了意义, 例如公历1月1日的新年, 11月11日的光棍节,爱好节日的人们也没有放过UNIX时间. UTC时间2001年9月9日1时46分40秒, UNIX时间迎来了第一个"亿禧年"(Billennium)[注释2], 1000000000. UTC时间2005年3月18日1时58分31秒则是UNIX时间的光棍节, 1111111111. 刚刚过去的1234567890, 对应公历的UTC2009年2月13日23时31分30秒, 对东一区以东的时区来说是2月14日情人节, 以西的时区来说则刚好落在黑色星期五. 传统上认为黑色星五不吉利的西方媒体, 针对此事进行了玩笑性的报道, 结果被一些居住在其他时区的人们误读成了"UNIX时间错误"。
丹麦哥本哈根的丹麦UNIX用户群组织庆祝UNIX"亿禧年" 图为当时所用的倒计时公告牌
无独有偶, 2012年7月13日也是一个黑色星期五, 而那天的UTC时间11时1分20秒对应着UNIX时间0x50000000(十六进制, 十进制值是1342177280). 不知到了那个时候, 会不会再次有人把它误解为又一次的UNIX时间错误?
2038年的问题才是混乱
UTC时间2033年5月18日3时33分20秒, 是UNIX时间的第二个"亿禧年"(Billenniumm), 即2000000000. 然而, 第三个"亿禧年"(Billennium)则不会毫无障碍的来临, 在那之前, 人们先得解决正在变得著名的2038年问题. 和本世纪初的千年虫(Y2K Bug)问题类似, 2038年问题(Y2K38 BUG)更隐蔽, 而且更难解决. 我们知道计算机内部的一切都是二进制的, 也就是说1234567890在32位系统的内存里实际上是01001001 10010110 00000010 11010010. 这串32位二进制数中, 最高位被用来表示正负符号, 0代表整数, 1代表负数, 所以它能表示的最大数字就是01111111 11111111 11111111 11111111, 即214748367, 对应公历的UTC时间2038年1月19日3时14分7秒. 到这天的凌晨3时14分8秒, UNIX时间会溢出并变成10000000 00000000 00000000 00000000(十进制值-214748368), 也就是UTC时间1901年12月13日20时45分52秒, 引起和千年虫类似的混乱.
2038年问题的动画演示
或许64位可以解决这个问题
2038年问题不仅比千年虫更隐蔽, 而且它的原因也更接近系统底层. 要解决这个问题, 最简单的方式是扩展UNIX时间的长度, 用64位数字来表示它. 64位二进制数的实际可用位数是63位, 最大表示到公历的UTC时间292277026596年12月4日. 如果那个时候人类文明还存在的话, 公元纪年很可能已经因为太难用而被抛弃了. 理想的情况是到2038年, 64位系统已经成为主流, 从而避免特意去修正这个问题所需要的大量开销. 否则, 人们就必须把新的64位时间拆分成两部分并分别保存在两个变量里, 这是一个麻烦而且效率低下的选择.
[注释1]: 就像很多其他的节日一样, 把UNIX的诞生日选在这天只是出于方便. 实际上, 最早的运行在PDP-7上的UNIX在1969年就已经完成了.
[注释2]: Billennium实际上是"十亿禧年", 但是这样听起来很奇怪, 所以我用"亿禧年"作为暂用名.