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

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

                            发布时间:2021-11-05 18:57:05来源:于振海网作者:于振海文章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
                            ****执行结果结束****

                            顶一下
                            2
                            50%
                            踩一下
                            2
                            50%
                            评论列表 发表评论
                            推荐文章
                            信彩