关于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修改数据库相关字段
关于PHP函数time() date() 和 strtotime() 的时区问题的更多相关文章
- php中的date和strtotime函数妙用
php中的两个常用的日期相关函数date和strtotime,相信大家一定不陌生.但我们平时使用都只是基本功能,什么时间戳变日期格式,日期格式变时间戳. 其实这两个函数还有更深的用法: 1.date函 ...
- php时间函数time(),date(),mktime()区别
php时间函数time(),date(),mktime()区别 浏览:1161 发布日期:2014/12/18 分类:系统代码 关键字: php时间函数 time() date()mktime() ...
- PHP 时间 date,strtotime ,time计算1970开始的第几天
首先,需要看你的php时区配置参数 方式1:更改php配置文件,然后从其fast-cgi或者php调用的地方: 方式2:date_default_timezone_set('PRC'); date函数 ...
- JavaScript 基础(七) 箭头函数 generator Date JSON
ES6 标准新增了一种新的函数: Arrow Function(箭头函数). x => x *x 上面的箭头相当于: function (x){ return x*x; } 箭头函数相当于匿名函 ...
- js中的函数,Date对象,Math对象和数组对象
函数就是完成某个功能的一组语句,js中的函数由关键字 function + 函数名 + 一组参数定义;函数在定义后可以被重复调用,通常将常用的功能写成一个函数,利用函数可以使代码的组织结构更多清晰. ...
- 玩转PHP(二)--PHP强大的时间函数:date()
PHP具有相对来说强大的时间函数date(),该方法有下列一系列参数: 例如: echo date("Y-m-d H:i:s"); //2015-01-09 13:03:30 如果 ...
- xe7 c++builder 日期时间头文件函数大全 date
c++builde r时间日期函数大全,在头文件System.DateUtils.hpp,不过没有IncMonth,因为这个函数定义在System.SysUtils.hpp里头了,唉 date,dat ...
- js匿名函数和date对象,math对象
匿名函数: <script type="text/javascript"> function (参数列表){ 要执行的语句块; } </script> 对象 ...
- 日期函数new Date()浏览器兼容性问题
项目上与时间相关的地方特别多,与时间格式相关都使用了moment.js轻量级日期处理库,在开发中出现了几次浏览器兼容性问题,所以总结一下new Date()和moment.js在各大浏览器中兼容性问题 ...
随机推荐
- activity的四种加载模式
在android里,有4种activity的启动模式,分别为: standard, singleTop, singleTask和singleInstance, 其中standard和singleTop ...
- jQ中对attr()方法的理解
在JS中设置节点的属性与属性值用到setAttribute(),获得节点的属性与属性值用到getAttribute(),而在jquery中,用一个attr()就可以全部搞定了,赞一个先 ^^jquer ...
- wsdl学习
本文来自 :迹忆 原文地址:http://www.onmpw.com/tm/xwzj/network_47.html 在刚开始学习Webservice的时候,发现里面涉及到的知识点还真不少,每一点单拿 ...
- iOS开发,URL编码和解码
URL传递数据中,如果含有中文,需要进行编码: NSString *urlEncodeString = [urlStr stringByAddingPercentEncodingWithAllowed ...
- django之分页、cookie装饰器
一.分页代码如下 from django.utils.safestring import mark_safe class Page: def __init__(self, current_page, ...
- 使Docker Container支持运行SWT程序
1, 下载安装JDK的docker container 我是从这个源下载已经做好的JDK8的container: https://registry.hub.docker.com/u/dockerfil ...
- Linux截屏工具scrot用法详细介绍
Scrot是Linux命令行中使用的截图工具,能够进行全屏.选取等操作,下面小编将针对Scrot截图工具的用法给大家做个详细介绍,通过操作实例来学习Scrot的使用. 在Linux中安装Scrot ...
- nginx 日志变量含义
log_format logstash "remote_addr | $time_local | $request | $status | $body_bytes_sent | " ...
- 【转载】 input 输入格式化
不多说直接 发链接 http://nosir.github.io/cleave.js/
- 有关uploadifive的使用经验
这段时间做了一个项目用到uploadifive上传控件,和uploadify不同,这个控件是基于HTML5的版本而不用支持falsh,因而移动端也可以使用. 整理用过的相关属性与方法: 属性 作用 a ...