太原PHP培训机构哪家好

太原达内IT教育

  php在2038年后datetime类也无法获得当前日期的解决

  由于php 32位使用int类型保存时间戳,也就是从1970 00:00:00到当前时间的秒数。

  而32位int数字的取值范围是-2147483648到2147483647。

  所以当时间戳为大值2147483647时,表示的时间是2038-01-19 03:14:07或北京时间2038-01-19 11:14:07(为了表述方便,下文中,将这个临界点时间称之为T0)。

  而当时间大于这个时间时,php很多内置函数都会出错。

  比如

  当日期和时间大于北京时间2038-01-19 11:14:07时

  time()函数,原本应该返回时间戳,现在会始终返回-1。

  date("Y-m-d H:i:s")函数,会返回1970-01-01 07:59:59(北京时间),其实也是因为time()=-1导致的,date默认的第二个参数就是time()。

  同样,mktime()等函数也会异常。

  上网查了解决办法,

  1、换用64位系统。这里说的64位系统,需要操作系统、web服务系统,以及PHP都要64位的。

  2、使用php5.2之后推出的DateTime类。

  首先说种方法,因为我的服务器建设在Windows系统上,然后又有几个自制插件,这些插件在php 64位下面可能不能使用,因此这个方法不能用。

  再说DateTime类,网上几乎几十篇文章都说使用DateTime类就能解决2038年问题。

  我在自己的服务器上测试了一下,使用DateTime类似乎确实可以让日期超过2038上限,各种转换,都没问题,这里我不具体说明,大家网上搜"php datetime",都有说明。

  但是,我在把服务器的时间设置为2040年4月18日的时候,发现,datetime类依然无法获取当前时间。代码如下:

  $date=new DateTime();

  echo$date->format('Y-m-d H:i:s');

  输出的还是1970-01-01 07:59:59

  但是,如果使用$date->setDate(2040,4,18)之后,再显示,再输出时间戳等,都是正常的代码如下:

  $date=new DateTime();

  $date->setDate(2040,4,18);

  $date->setTime(10,24,11);

  echo$date->format('Y-m-d H:i:s')."\r\n";

  echo$date->format('U')."\r\n";

  这时输出时间2040-04-18 10:24:11,以及时间戳2218328651都是正常的。

  问题在于,datetime类可以解决2038年之后的时间的各种运算和转换,但是当系统日期在2038年那个T0时间之后,php系统根本无法获取当前时间。

  我还试了new DateTime("today");new DateTime('+2 days');new DateTime('tomorrow');等等,都无法获取今天,明天,后天等日期。

  这时,整个php系统无法获取当前的年月日和时间。

  然后我开始在php的系统数组$_SERVER中寻找,看看哪里能找到和时间相关的内容,终于被我找到一个$_SERVER["REQUEST_TIME"],这个实际上是一个记录用户刷新页面时php相应时刻的时间。它的值,在T0之前,和time()是一致的,但是,当T0之后,它就变成负数了。那么,怎么通过$_SERVER["REQUEST_TIME"]来获取真实的时间戳呢?

  很简单,32位int数字的取值范围是-2147483648到2147483647,转成2进制就会发现,其实是高位用作符号位,高位0表示正数,高位1表示负数,当数字达到2147483647后,二进制就是01111111 11111111 11111111 11111111(31个1),这时就是T0时刻的时间戳,继续+1以后,变成了10000000000000000000000000000000(31个0),如果是无符号32位整数,就是2147483648(正数)但是在有符号的整数里,高位1表示负数,就是-2147483648(负数),而$_SERVER["REQUEST_TIME"]的特性是根据时间的推移进行累加。所以,它的时间线如下:

  T0之前:它等于1970 00:00:00到当前时间的秒数,和time()相同

  T0时:它等于2147483647

  T0后1秒:它等于2147483647+1=2147483648被表示为-2147483648我们把-2147483648记作T1,T1=T0+1秒的时刻

  T0后N秒:-2147483648-1+N

  所以,当$_SERVER["REQUEST_TIME"]<0时,真正的时间戳为$_SERVER["REQUEST_TIME"]-(-2147483648)+2147483647。

  其中$_SERVER["REQUEST_TIME"]-(-2147483648)表示T1(变成负数,即T0+1秒)时刻到当前时间过了多少秒。

  据此,写出一个新的取代time()的函数,该函数在系统时间超过T0时,也能返回正确的时间戳,但是它的范围是无符号32位上限4294967295,北京时间2106-02-07 06:28:15。在这个时间之前,应该都可以正常使用。

  function sunTime(){

  if($_SERVER["REQUEST_TIME"]>0){

  $t=$_SERVER["REQUEST_TIME"];

  }else{

  $t0=PHP_INT_MAX;//第2147483647秒再过一秒为2147483648秒,但高位变成1,系统中为-2147483648

  $t1=0-$t0-1;//t0后面1秒,瞬间变成负数,值为-2147483648

  $t2=($_SERVER["REQUEST_TIME"]);//虽然$_SERVER["REQUEST_TIME"]变成了负数,但是系统依然通过+1秒来计时

  $t=$t2-$t1+$t0."";//t2-t1就是变成负数后过了多少秒,t0就是变成负数前的秒数。

  }

  $date=new datetime(" ".$t);

  $timemark=$date->format("U");

  return$timemark;

  }

  所以,目前网上很多人都以为使用DateTime类可以解决问题,殊不知等时间真正到了2038那个时间之后,php系统获得当前时间都会出错。而我这方法也是目前网上存在的方法。

领取试听课
每天限量名额,先到先得
温馨提示:为不影响您的学业,来 太原其他培训 校区前请先电话或QQ咨询,方便我校安排相关的专业老师为您解答
  • 详情请进入 太原达内IT教育

关于我们 | 招生信息 | 新闻中心 | 学校动态

版权所有:搜学搜课(www.soxsok.com)