Chad 2010-01-25

今天由于要执行一些比较变态的任务,要用PHP里的mktime()来创建尽可能大的时间戳。本来想用当前时间加个一千年的,但发现下面的代码返回false:

 

Code - PHPPlain Text
 
  1. $baseTime = time();  
  2. $newTime = mktime(0, 0, 0, date("m",$baseTime), date("d",$baseTime), date("Y",$baseTime) + 1000);// returns FALSE  



很明显是mktime()的参数和返回值都有上限了。查了一下PHP Reference,发现原来mktime()的year参数的有效范围是1901到2038,不过此限制自 PHP 5.1.0 起已被克服了。问题是我机上用的是PHP 5.2.5,也同样受限了。。。

然后,我发现不只是year参数有上限,当year是2038时,连其它参数也受限了。很明显,这里有一个“极限时间”。为了测出这个极限,我便玩了一会猜数游戏。。。最后,发现下面这一组参数就是极限,再加一秒都会出错:
 

Code - PHPPlain Text
 
  1. $newTime = mktime(3, 14, 7, 1, 19, 2038);// returns 2147483647  



这个日期其实本身没什么特别的,只是从1970年1月1日0时0分0秒到它,有共2147483647这么多秒。我觉得奇怪,就在网上查了一下,结果发现特别的正是这个数字——2147483647。这个数等于2的31次方减1,并于1772年被瑞士人欧拉证明了是一个质数,也是到目前为止人类所发现的最大的质数1

当然,对我来说最重要的是它是一个极限,它是32位的操作系统里最大的有符号正整数。正如上面所展示的,只要是用了32位Unix时间表示方法的操作系统及软件,能表示的最大时间是2038年1月19日3时14分7秒。而在那之后,只要再加一秒,2147483647就会变成-2147483648(机械数是由01111111 11111111 11111111 11111111变成10000000 00000000 00000000 00000000),年份就会变回1901,这就是2038问题(Y2K38)。不过,目前已经有一些解决方案个问题的办法了,例如使用无符号整数表示在32位操作系统和软件里表示时间,或者是直接使用64位操作系统和软件。但是,这些方法都不能轻易解决目前正在使用的32位操作系统和软件里所存在的Y2K38问题,多多少少都有不兼容的问题2

今后即使使用64位的操作系统和软件,在表示时间的时候,同样会面临着与Y2K和Y2K38同质的问题,只是时间相对较后(大概可以表示到公元300000年)。但是我认为用64位的已经绝对够了,因为没人会知道现在的计算机系统会在什么时候退出历史的舞台。



1. http://en.wikipedia.org/wiki/2147483647
2. http://en.wikipedia.org/wiki/Year_2038_problem