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

$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修改数据库相关字段

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

  1. php中的date和strtotime函数妙用

    php中的两个常用的日期相关函数date和strtotime,相信大家一定不陌生.但我们平时使用都只是基本功能,什么时间戳变日期格式,日期格式变时间戳. 其实这两个函数还有更深的用法: 1.date函 ...

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

    php时间函数time(),date(),mktime()区别   浏览:1161 发布日期:2014/12/18 分类:系统代码 关键字: php时间函数 time() date()mktime() ...

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

    首先,需要看你的php时区配置参数 方式1:更改php配置文件,然后从其fast-cgi或者php调用的地方: 方式2:date_default_timezone_set('PRC'); date函数 ...

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

    ES6 标准新增了一种新的函数: Arrow Function(箭头函数). x => x *x 上面的箭头相当于: function (x){ return x*x; } 箭头函数相当于匿名函 ...

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

    函数就是完成某个功能的一组语句,js中的函数由关键字 function + 函数名 + 一组参数定义;函数在定义后可以被重复调用,通常将常用的功能写成一个函数,利用函数可以使代码的组织结构更多清晰. ...

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

    PHP具有相对来说强大的时间函数date(),该方法有下列一系列参数: 例如: echo date("Y-m-d H:i:s"); //2015-01-09 13:03:30 如果 ...

  7. xe7 c++builder 日期时间头文件函数大全 date

    c++builde r时间日期函数大全,在头文件System.DateUtils.hpp,不过没有IncMonth,因为这个函数定义在System.SysUtils.hpp里头了,唉 date,dat ...

  8. js匿名函数和date对象,math对象

    匿名函数: <script type="text/javascript"> function (参数列表){ 要执行的语句块; } </script> 对象 ...

  9. 日期函数new Date()浏览器兼容性问题

    项目上与时间相关的地方特别多,与时间格式相关都使用了moment.js轻量级日期处理库,在开发中出现了几次浏览器兼容性问题,所以总结一下new Date()和moment.js在各大浏览器中兼容性问题 ...

随机推荐

  1. The Same Game-POJ1027模拟

    The Same Game Time Limit: 1000MS Memory Limit: 10000K Description The game named "Same" is ...

  2. 我的git与github学习历程

    因为想要知道如何把代码放到github上,所以就百度了一下,然后找到一个<如何从github上面拷贝源码>的文章,就先进行练习了下   1.首先到git官网下载git版本控制工具的安装包, ...

  3. NOI 动态规划题集

    noi 1996 登山 noi 8780 拦截导弹 noi 4977 怪盗基德的滑翔翼 noi 6045 开餐馆 noi 2718 移动路线 noi 2728 摘花生 noi 2985 数字组合 no ...

  4. sendEmail报错:at /usr/share/perl5/vendor_perl/IO/Socket/SSL.pm

    sendEmail发送邮件是出现以下报错: *******************************************************************  Using the ...

  5. CentOS系统启动流程

    CentOS系统启动流程 POST --> Boot Sequence(BIOS) --> Boot Loader(MBR) --> kernel(ramdisk) --> r ...

  6. 常用open api

    SNS类网站API Facebook - http://developers.facebook.com/ 人人网开放平台 - http://dev.renren.com/ 51.com开放平台 - h ...

  7. inline-boock的默认间距

    1 2 3 4 div{width:900px;} div li{ display:inline-block; width:300px;} <ul>     <li></ ...

  8. JavaScript的chapterI

    JavaScript是一种由web浏览器进行解析和执行脚本语言,包括ECMAScript,DOM,BOM. JavaScript的最大作用是赋予页面动作,让页面动起来,已经动态的处理页面的数据. 应用 ...

  9. 【转载】DOS 系统和 Windows 系统有什么关系?为什么windows系统下可以执行dos命令?

    作者:bombless 因为不同的系统都叫 Windows ,这些系统在界面上也有一定连续性并且因此可能造成误解,所以有必要稍微梳理一下几个不同的 Windows 系统.首先是 DOS 上的一个图形界 ...

  10. 微信小程序-画布组件

    canvas 画布. 注: canvas 标签默认宽度300px.高度225px 同一页面中的 canvas-id 不可重复,如果使用一个已经出现过的 canvas-id,该 canvas 标签对应的 ...