于振海网——于振海的个人博客搜索

2038年以后,在64位Windows中,PHP获取真实时间的一种解决方法

发布时间:2019年10月16日  更新时间:2023年9月25日
作者:于振海  文章ID:40763  浏览:

    最近无聊,考虑到2038年之后,PHP如何获取当前时间的问题。

    比如把电脑时间改成2050年,PHP时间系统乱套了。

    本以为在windows系统中,只需把操作系统、Apache和PHP都换成64位的就能解决问题,经过测试,其实不是。

    不同的操作系统和不同版本的Apache、PHP会出现不同的结果:

    64位windows2003、32位Apache2.2.31、32位PHP5.4.45,2038年之后PHP的date()始终返回1970-01-01 07:59:59,不会变化。

    64位windows2003、64位Apache2.2.34、64位PHP5.4.45,系统时间2050年,PHP的date()返回1914年,是变化的,time()是负数,但是会随着时间不断加1。PHP_INT_SIZE是4,PHP_INT_MAX是2147483647。date()超过2147483647还是出错。

    64位windows7、64位Apache2.4.41、64位PHP7.2.23,系统时间2050年,PHP的date()返回1914年,是变化的,time()是负数,但是会随着时间不断加1。PHP_INT_SIZE是8,PHP_INT_MAX是9223372036854775807。date()超过2147483647不会出错。唯独time()还是负数,获取时间还是出错。

    虽然是负数,但正常走时,这就好办了。下面是两张原理图:

    过了47秒之后,有如下规律:

    真实时间c = 47 + 多出的秒数b

    多出的秒数b = 47 + PHP时间a + 2

    整理一下:

    因为c = 47 + b ,b = 47 + a + 2

    所以c = 47 + 47 + 2 + a

    暂且叫这种方法为振海法吧,运用到PHP,写了realtime()函数代替time(),并附上测试代码和测试结果:

//////////PHP代码开始//////////

<?php
if(!function_exists("realtime"))
{
    function realtime()
    {
        $nowtime = time();
        if($nowtime < 0)
        {
            return 2147483647 + 2147483647 + 2 + $nowtime;
        }
        else
        {
            return $nowtime;
        }
    }
}

//64位php7.0之后的用法
echo time()." ".realtime()." //time()和realtime()的值,系统时间调到2050年,time()负数说明是32位的。<br />\r\n";
echo date("Y-m-d H:i:s",2556115199)." //如果返回2050-12-31 23:59:59,那么date()没有问题,能处理64位。如果返回1914-11-25 09:31:43,那么date()只能处理32位。<br />\r\n";
echo date("Y-m-d H:i:s", time())." //date('Y-m-d H:i:s', time())的时间。<br />\r\n";
echo date("Y-m-d H:i:s", realtime())." //date('Y-m-d H:i:s', realtime())的时间。<br />\r\n";
echo gmdate("Y-m-d H:i:s", time())." //gmdate('Y-m-d H:i:s', time())的时间。<br />\r\n";
echo gmdate("Y-m-d H:i:s", realtime())." //gmdate('Y-m-d H:i:s', realtime())的时间。<br />\r\n";
echo PHP_INT_SIZE." ".PHP_INT_MAX." //PHP_INT_SIZE和PHP_INT_MAX的值。<br />\r\n";

//64位PHP7.0之前的用法
$newdate = new DateTime("@".realtime());
$realdate = $newdate->format("Y-m-d H:i:s");
echo $realdate." //DateTime类的时间。";

//////////PHP代码结束//////////

//////////执行结果开始//////////

    环境:Windows2003-x64  Apache-2.2.34-VC10-x64  php-5.4.45-VC9-x64

    Windows系统时间:2050-10-16 13:28

    执行结果:

    -1745456344 2549510952 //time()和realtime()的值,系统时间调到2050年,time()负数说明是32位的。
    1914-11-25 17:31:43 //如果返回2050-12-31 23:59:59,那么date()没有问题,能处理64位。如果返回1914-11-25 09:31:43,那么date()只能处理32位。
    1914-09-10 07:00:56 //date('Y-m-d H:i:s', time())的时间。
    1914-09-10 07:00:56 //date('Y-m-d H:i:s', realtime())的时间。
    1914-09-09 23:00:56 //gmdate('Y-m-d H:i:s', time())的时间。
    1914-09-09 23:00:56 //gmdate('Y-m-d H:i:s', realtime())的时间。
    4 2147483647 //PHP_INT_SIZE和PHP_INT_MAX的值。
    2050-10-16 05:29:12 //DateTime类的时间。

    ----

    环境:Windows7-x64  Apache-2.4.41-VC15-x64  PHP-7.2.23-VC15-x64

    Windows系统时间:2050-10-16 13:07

    执行结果:

    -1745457669 2549509627 //time()和realtime()的值,系统时间调到2050年,time()负数说明是32位的。
    2050-12-31 15:59:59 //如果返回2050-12-31 23:59:59,那么date()没有问题,能处理64位。如果返回1914-11-25 09:31:43,那么date()只能处理32位。
    1914-09-09 22:38:51 //date('Y-m-d H:i:s', time())的时间。
    2050-10-16 05:07:07 //date('Y-m-d H:i:s', realtime())的时间。
    1914-09-09 22:38:51 //gmdate('Y-m-d H:i:s', time())的时间。
    2050-10-16 05:07:07 //gmdate('Y-m-d H:i:s', realtime())的时间。
    8 9223372036854775807 //PHP_INT_SIZE和PHP_INT_MAX的值。
    2050-10-16 05:07:07 //DateTime类的时间。

//////////执行结果结束//////////

    不考虑32位版本,从结果来看,在64位PHP7.0之前,realtime()函数和DateTime类一起用没有问题。在64位PHP7.0之后,realtime()函数和date()函数一起用没有问题,起码还能用到2038 + (2038 - 1970) = 2106年。

    不知道64位windows2008、2012、2016等time()是不是返回负数。抽空再测试。

----------分割线----------

2019.10.19更新

    今天突然发现64位7.0之后的php中,$_SERVER["REQUEST_TIME"]是完整的64位时间戳,超过2038年不会返回负数。在当前的php版本中,用下面的$rtime变量替换time()函数,可以完美解决2038年问题。

//////////php代码开始//////////

<?php
//64位php7.0之后的用法
$rtime = $_SERVER["REQUEST_TIME"];
echo $rtime." //rtime的值。<br />\r\n";
echo date("Y-m-d H:i:s", $rtime)." //date('Y-m-d H:i:s', rtime)的时间。<br />\r\n";
echo gmdate("Y-m-d H:i:s", $rtime)." //gmdate('Y-m-d H:i:s', rtime)的时间。<br />\r\n";

//////////php代码结束//////////

//////////执行结果开始//////////

    环境:Windows7-x64  Apache-2.4.41-VC15-x64  PHP-7.2.23-VC15-x64

    Windows系统时间:2099-10-19

    执行结果:

    4096073963 //rtime的值。
    2099-10-19 06:19:23 //date('Y-m-d H:i:s', rtime)的时间。
    2099-10-19 06:19:23 //gmdate('Y-m-d H:i:s', rtime)的时间。

//////////执行结果结束//////////

-----

2019.10.22更新

    在32位windows2003系统和32位PHP5.3.45中,用$_SERVER['REQUEST_TIME']可以获取正常的负数时间。和64位版本中time()的值一样。写了一个函数,支持32位或64位老版本的windows2003和PHP5.4.45。
    用下面的用time2()替换time()函数,用date2()替换date()函数,用gmdate2()替换gmdate()函数,顺便改了织梦CMS的MyDate()函数,全部能支持到2038年以后。

/////PHP代码开始/////

<?php

//时区
$cfg_cli_time = 8;

//支持2038年之后的正确时间,用time2()替换time()函数
if(!function_exists('time2'))
{
    function time2()
    {
        $currenttime = time();//64位PHP用time()或$_SERVER['REQUEST_TIME']都可以,32位PHP只能用用$_SERVER['REQUEST_TIME']
        if($currenttime < 0)
        {
            return 2147483647 + 2147483647 + 2 + $currenttime;
        }
        else
        {
            return $currenttime;
        }
    }
}

//支持2038年之后的正确时间,用date2()替换date()函数
if (!function_exists('date2'))
{
    function date2($format='Y-m-d H:i:s', $timest=0)
    {
        global $cfg_cli_time;
        if(empty($format))
        {
            $format = 'Y-m-d H:i:s';
        }
        $addtime = $cfg_cli_time * 3600;
        if(empty($timest))
        {
            $newtimestamp = time2() + $addtime;
        }
        else
        {
            $newtimestamp = $timest + $addtime;
        }
        $newdatetime = new DateTime("@".$newtimestamp);
        return $newdatetime->format($format);
    }
}

//支持2038年之后的正确时间,用gmdate2()替换gmdate()函数
if (!function_exists('gmdate2'))
{
    function gmdate2($format='Y-m-d H:i:s', $timest=0)
    {
        if(empty($format))
        {
            $format = 'Y-m-d H:i:s';
        }
        if(empty($timest))
        {
            $newtimestamp = time2();
        }
        else
        {
            $newtimestamp = $timest;
        }
        $newdatetime = new DateTime("@".$newtimestamp);
        return $newdatetime->format($format);
    }
}

//返回格林威治标准时间
if (!function_exists('MyDate'))
{
    function MyDate($format='Y-m-d H:i:s', $timest=0)
    {
        global $cfg_cli_time;
        $addtime = $cfg_cli_time * 3600;
        if(empty($format))
        {
            $format = 'Y-m-d H:i:s';
        }
        return gmdate2($format, $timest+$addtime);
    }
}

echo time()." //time()<br />\r\n";
echo time2()." //time2()<br />\r\n";
echo date2()." //date2()<br />\r\n";
echo gmdate2()." //gmdate2()<br />\r\n";
echo MyDate('', 2549948733)." //正常返回2050-10-21 15:05:33<br />\r\n";

/////PHP代码结束/////

////执行结果开始/////

环境:Windows2003-x64  Apache-2.2.34-VC10-x64  php-5.4.45-VC9-x64

当前系统时间:2050-10-21 15:08:18

-1745018398 //time()
2549948898 //time2()
2050-10-21 15:08:18 //date2()
2050-10-21 07:08:18 //gmdate2()
2050-10-21 15:05:33 //正常返回2050-10-21 15:05:33

/////执行结果结束/////

**********20210825更新**********
    今天发现在低版本Apache和PHP中,$_SERVER["REQUEST_TIME_FLOAT"]可以正确获取时间,唯一一个正确的,非常难得。

****测试代码开始****
<?php

echo time()."<br />\r\n";

echo microtime()."<br />\r\n";

echo $_SERVER["REQUEST_TIME"]."<br />\r\n";

echo $_SERVER["REQUEST_TIME_FLOAT"]."<br />\r\n";

//支持2038年之后的正确时间,用time2()替换time()函数
if(!function_exists('time2'))
{
 function time2()
 {
  $currenttime = explode('.', $_SERVER['REQUEST_TIME_FLOAT']);
  return $currenttime[0];
 }
}

echo time2()."<br />\r\n";

$newdate = new DateTime("@".time2());
$realdate = $newdate->format("Y-m-d H:i:s");
echo $realdate."<br />\r\n";
****测试代码结束****
****执行结果开始****
日期:2021-08-23    Windows-2008-r2-企业版-64位    Apache-2.2.34-64位    PHP-5.4.45-64位
结果:
1629692951
0.23484500 1629692951
1629692951
1629692951.234
1629692951
2021-08-23 04:29:11

日期:2050-08-23    Windows-2008-r2-企业版-64位    Apache-2.2.34-64位    PHP-5.4.45-64位
结果:
-1750125419
0.30849000 -1750125419
-1750125419
2544841877.308
2544841877
2050-08-23 04:31:17
****执行结果结束****

发表评论  挑错  文章投稿  联系我
  • 上一篇:新中国成立70周年大阅兵儿童画
  • 下一篇:三个数得出6的振海解法
  • 【推荐文章】

  • 第一次收到2345的推广费

    2012年8月8日 晴 今天收到2345的100元钱,虽然不多,但这是做2345推广以来,第一次收...

  • 春雨洗柳

    春雨洗柳 柳叶娇绿雨潇潇, 绿雨潇潇万丝漂。 万丝飘落春时暖, 落春时暖柳叶娇。 写...

  • 20140514于致远扣篮

    拍摄日期:20140514...

  • 主板电容爆浆原因分析

    对于很多人来说电容爆浆这个词已经不再陌生,很多人也见过电容爆浆的场面,其实电容爆...

  • 主板电容鼓包的症状及危害

    主板电容鼓包的症状及危害 1.电脑无故自动重启,特别是电脑忙的时候。 2.开机时候要连...

  • php中str_replace出现乱码原因分析

    乱码问题是汉字编码和str_replace的工作方引起的,因为一个汉字是占两个字节的,全角...

  • 【最新文章】

  • 元宵节晚上供养点蜡烛-2013年
  • 新买的手表 ocw-t100td-1ajf
  • 于致远照片-20130224
  • 三星scx-4300:paper jam 2,check inside
  • 第一次收到2345的推广费
  • 外链不在多,而在精
  • 春雨洗柳
  • 高频ups输出50Hz的秘密
  • ftp上传下载文件,大小改变的问题
  • 20140509于致远大摆pose
  • 20140514于致远扣篮
  • 20140523于致远玩水桶
  • 主板电容爆浆原因分析
  • 主板电容鼓包的症状及危害
  • php中str_replace出现乱码原因分析