令人困惑的strtotime

作者: Laruence( ) 本文地址: http://www.laruence.com/2018/07/31/3188.html 转载请注明出处

经常会有人被strtotime结合-1 month, +1 month, next month的时候搞得很困惑, 然后就会觉得这个函数有点不那么靠谱, 动不动就出问题. 用的时候就会很慌…

这不, 刚刚就有人在微博上又问我:

鸟哥,今天是2018-07-31 执行代码:

date("Y-m-d",strtotime("-1 month"))

怎么输出是2018-07-01?

好的吧, 虽然这个问题看起来很迷惑, 但从内部逻辑上来说呢, 其实是”对”的, 你先别着急哈, 让我慢慢讲:

我们来模拟下date内部的对于这种事情的处理逻辑:

1. 先做-1 month, 那么当前是07-31, 减去一以后就是06-31. 2. 再做日期规范化, 因为6月没有31号, 所以就好像2点60等于3点一样, 6月31就等于了7月1

是不是逻辑很”清晰”呢? 我们也可以手动验证第二个步骤, 比如:

var_dump(date("Y-m-d", strtotime("2017-06-31")));
//输出2017-07-01

也就是说, 只要涉及到大小月的最后一天, 都可能会有这个迷惑, 我们也可以很轻松的验证类似的其他月份, 印证这个结论:

var_dump(date("Y-m-d", strtotime("-1 month", strtotime("2017-03-31"))));
//输出2017-03-03
var_dump(date("Y-m-d", strtotime("+1 month", strtotime("2017-08-31"))));
//输出2017-10-01
var_dump(date("Y-m-d", strtotime("next month", strtotime("2017-01-31"))));
//输出2017-03-03
var_dump(date("Y-m-d", strtotime("last month", strtotime("2017-03-31"))));
//输出2017-03-03

那怎么办呢?

从PHP5.3开始呢, date新增了一系列修正短语, 来明确这个问题, 那就是”first day of” 和 “last day of”, 也就是你可以限定好不要让date自动”规范化”:

var_dump(date("Y-m-d", strtotime("last day of -1 month", strtotime("2017-03-31"))));
//输出2017-02-28
var_dump(date("Y-m-d", strtotime("first day of +1 month", strtotime("2017-08-31"))));
////输出2017-09-01
var_dump(date("Y-m-d", strtotime("first day of next month", strtotime("2017-01-31"))));
////输出2017-02-01
var_dump(date("Y-m-d", strtotime("last day of last month", strtotime("2017-03-31"))));
////输出2017-02-28

那如果是5.3之前的版本(还有人用么?), 你可以使用mktime之类的, 把所有的日子忽略掉, 比如都限定为每月1号就可以了, 只不过就不如直接用first day来的更加优雅.

现在, 搞清楚了内部原理, 是不是就不慌了? :)

Comments

2018/07/31, 沈唁志 writes: 鸟哥更文了!2018/07/31, 莫非 writes: 不慌,了2018/07/31, mengkang writes: 匹配这么多种情况,还有这么长的字符串,我还是用mktime吧,啥时候给博客加上微博表情包就好了。2018/07/31, Charles writes: 谢谢鸟哥回复2018/07/31, loadinger writes: 鸟哥竟然更新了... 最近是玩农药玩得少了呀,这可不行.再说dota2,马上ti了,训练不能少~!2018/07/31, 侉帮子 writes: 鸟哥终于更新博客了。2018/07/31, 老郭博客 writes: 的确不慌了、2018/07/31, 白菜 writes: 感觉还是mktime好用,这种情况还是比较特殊的。不够灵活。2018/07/31, dream-fei writes: 不慌了,原来如此2018/07/31, Tonight writes: 鸟哥,请问下first day of/last day of后面的关键词,在底层是如何解析的?2018/08/01, jack writes: 额 其实还是很方啊,我一直以为是这样的,2.28 +1 month = 3.31 结果是3.28 统计的时候,要判断是大小月 还要判断上个月是大小月,然后还得今天是月末,还是月初。。。。 之前在php手册上看到 这个 [kumar AT swatantra.info Swatantra Kumar ] 这位同学在5 years ago的说的 var_dump(date("Y-m-d", strtotime("-1 month", strtotime("2017-03-31")))); //输出2017-03-03 只是感觉不对劲 这能归结为一个bug么。鸟大大 。2018/08/01, tanteng writes: 终于更新了!2018/08/01, tanteng writes: 终于更新了!Copyright © 2010 风雪之隅 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)

Related Posts:

HTTPOXY漏洞说明让你的PHP7更快(GCC PGO)在PHP中使用协程实现多任务调度GCC优化引起的一个”问题”Curl的毫秒超时的一个”Bug”Weibo LAMP演变 – 6月在上海分享的PPT一个小玩意PHP-Valgrind的介绍PHP浮点数的一个常见问题的解答Yaf and Phalcon, which is faster?Yar – 并行的RPC框架(Concurrent RPC framework)

文章来源:

Author:Laruence
link:http://www.laruence.com/2018/07/31/3188.html