关于PHP函数time() date() 和 strtotime() 的时区问题

最近项目中有个需求, 要记录新注册用户的次日登录情况, 于是写出了如下代码:

$create_time = ‘用户注册时间‘; //格式 Y-m-d H:i:s

$time = time();

$lasttime = date(‘Y-m-d H:i:s‘, $time);

$current_day = floor($time / 86400);

$create_day = floor( strtotime($create_time) / 86400 );

$days = $current_day - $create_day;

switch ($days)
{
    case 1:
        $values[‘2day‘] = 1; break; //次日登陆
    case 6:
        $values[‘7day‘] = 1; break; //七日登陆
    case 14:
        $values[‘15day‘] = 1; break; //十五日登陆
} 

//执行SQL修改数据库相关字段

这段代码放到线上后, 出现了奇怪的BUG, 明明是当天注册的用户, 却出现了有次日登录的情况. 排查代码没有发现问题, 于是暂时搁置去忙其它事情. 然后在第6天时, 竟然又出现了有七日登陆的数据. 于是开始和同事正式解决这个问题, 最终发现是由于函数的时区原因导致, 具体如下:

time()  返回自从 Unix 纪元(格林威治时间 1970 年 1 月 1 日 00:00:00)到当前时间的秒数.

上面是 time() 函数在手册中的说明, 重点是格林威治时间, time() 始终返回的是格林威治时间的时间戳. 当PHP设置过时区后, date() 在格式化时间的操作中会将 (当前时区的时间 - 格林威治时间) 的偏移量自动添加进去, 按东八区的时间算也就是8小时. strtotime() 同样会自动将时区的偏移量加入处理操作中. 所以这时上面代码中 strtotime($create_time) 得到的同样是格林威治时间. $current_day 与 $create_day 现在都是按照格林威治时间计算的天数, 而BUG也就出现在这里.

比如当前时间为 2015-02-02 07:00:00 那么格林威治时间为 2015-02-01 23:00:00 (当前时间减去8小时)

当前时间为  2015-02-02 09:00:00  格林威治时间为 2015-02-02 01:00:00

再通过 floor() 处理后, 就相当于格林威治时间的 2015-02-02 与 2015-02-01, 中间相差一天.

所以如果用户在7点多注册, 而在9点再次登录的情况下, $current_day - $create_day = 1.

测试代码如下:

//date_default_timezone_set(‘UTC‘); //设置为格林威治时间

date_default_timezone_set(‘Asia/Shanghai‘); //设置为东八区上海时间

$a = floor( strtotime(‘2015-02-02 07:00:00‘) / 86400 );

$b = floor( strtotime(‘2015-02-02 09:00:00‘) / 86400 );

echo $b - $a; // 结果 1 

//将格林威治时间打开, 注释掉上海时间, 结果输出为 0.

最终解决BUG后的代码如下:

$create_time = ‘用户注册时间‘; //格式 Y-m-d H:i:s

$time = time();

$lasttime = date(‘Y-m-d H:i:s‘, $time);

//时间戳总是获取的格林威治时间, strtotime()会自动添加当前时区的偏移量, 这里因时区问题导致天数计算出现一天的误差, 所以在处理时间戳时增加时区的偏移量
$current_day = floor( ($time + date(‘Z‘)) / 86400 );

$create_day = floor( (strtotime($create_time) + date(‘Z‘)) / 86400 );

$days = $current_day - $create_day;

switch ($days)
{
    case 1:
        $values[‘2day‘] = 1; break; //次日登陆
    case 6:
        $values[‘7day‘] = 1; break; //七日登陆
    case 14:
        $values[‘15day‘] = 1; break; //十五日登陆
} 

//执行SQL修改数据库相关字段
时间: 2025-01-18 06:32:24

关于PHP函数time() date() 和 strtotime() 的时区问题的相关文章

时间函数date(),mktime(),strtotime()

$begin_time = '2018-8'; //指定月份月初时间戳 $month_start = strtotime($begin_time); //指定月份月末时间戳 $month_end = mktime(23, 59, 59, date('m', strtotime($begin_time))+1, 00); //获取本周是第几周 $date = date('Y-m-d',time()); $date_week = date("W", strtotime($date)); /

php时间函数time(),date(),mktime()区别

php时间函数time(),date(),mktime()区别 浏览:1161 发布日期:2014/12/18 分类:系统代码 关键字: php时间函数 time() date()mktime() php时间函数time(),date(),mktime()区别php :time(),date(),mktime()日期与时间函数库{经常会忘却掉} checkdate : 验证日期的正确性. date : 将服务器的时间格式化. strftime : 将服务器的时间本地格式化. getdate :

PHP 时间 date,strtotime ,time计算1970开始的第几天

首先,需要看你的php时区配置参数 方式1:更改php配置文件,然后从其fast-cgi或者php调用的地方: 方式2:date_default_timezone_set('PRC'); date函数用于日期函数的获取,这里需要注意的,date得到的我们可以理解为概念时间,跟地区有关系.如北京时间和伦敦时间同一个时刻对应不同的时间有8小时的时差,北京时间早8小时. time和strtotime得到的是物理时间,不存在和地区的联系,全球统一. 在项目有需要计算1970开始的第几天,这里就出现了问题

JavaScript 基础(七) 箭头函数 generator Date JSON

ES6 标准新增了一种新的函数: Arrow Function(箭头函数). x => x *x 上面的箭头相当于: function (x){ return x*x; } 箭头函数相当于匿名函数,并且简化了函数定义.一种像上面的,只包含一个表达式, 连{ ... }和return都省略掉了.还有一种可以包含多条语句,这时候就不能省略{ ... }和return: x =>{ if(x > 0){ return x * x; }else{ return -x *x; } } 如果参数不是

php中的time(),date(),mktime(),strtotime()

time():返回当前的Unix时间戳: date():格式化一个本地的时间戳: mktime(时,分,秒,月,日,年):取得一个日期的时间戳: strtotime():将任何英文文本的日期时间描述解析为Unix时间戳 <?php echo time(); echo date('Y-m-d H:i:s',time()); echo mktime(13,54,55,9,18,2015); echo strtotime("now"); echo strtotime("10

js中的函数,Date对象,Math对象和数组对象

函数就是完成某个功能的一组语句,js中的函数由关键字 function + 函数名 + 一组参数定义;函数在定义后可以被重复调用,通常将常用的功能写成一个函数,利用函数可以使代码的组织结构更多清晰. 其语法结构为 function funName (arg0, arg1, … argN){        //statements    } function say_hello (name, msg){ alert(“hello”+ name + “:”+ msg); } say_hello(“d

自定义的plot函数参数date坐标模型[x,y]的使用建议

调用plot函数的方法如下: var plot = $.plot(placeholder, data, options) 分析:data应该是data series的一个数组:[ [x1, y1], [x2, y2], ... ] data是从后台传数据过来,通常是用ajax去获取的json数据,那么我们就可以在java后台去考虑xy坐标模型的构造了. 这里我先提一下JSON中的两种数据结构:对象和数组. 对象以"{"(左括号)开始,"}"(右括号)结束.每个&qu

玩转PHP(二)--PHP强大的时间函数:date()

PHP具有相对来说强大的时间函数date(),该方法有下列一系列参数: 例如: echo date("Y-m-d H:i:s"); //2015-01-09 13:03:30 如果时间小时错误,修改php.ini,到其中的 ;date.timezone,删掉前面的分号,并改为date timezone = PRC.保存,重启Apahce服务即可 红色部分为一些常用的 年: y 2 位数字表示的年份 例如:99 或 03 Y 4 位数字完整表示的年份 例如:1999 或 2003 L 是

date命令及Centos时区更改

大家都知道通过通过date命令可以查看时间比如 date     查看系统当前时间 date +%Y    显示年份 2017 date +%y    显示年份 17 date +%m    显示月    5 date +%d    显示日    12 date +%w    显示星期    5 date +%H    显示时 date +%M    显示分 date +%S    显示秒 date +%F    显示年-月-日 date +%T    显示 时:分:秒 而有时候系统的时区是错误