当前位置:于振海网 > 随笔 >

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

发布时间:2019-10-16 18:08来源:于振海网作者:于振海文章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

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

顶一下
0
0%
踩一下
0
0%
评论列表 发表评论
推荐文章