- 本文地址: http://www.laruence.com/2018/07/31/3207.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来的更加优雅.
现在, 搞清楚了内部原理, 是不是就不慌了? 🙂
前几天,我走进大自然,没有来自城市的喧闹声,没有头痛,只有我和大自然的声音。
气动隔膜泵
正好用到这个,学习了。
确实很容易出现坑
不错支持一下
学习了
分享的不错
请教一下,如果想获取上周的周一,这种时间,strtotime 有没有类似的修正短语呢
已采坑
[…] 后面再网上找到了一篇文章, 讲解这个问题的 http://www.laruence.com/2018/07/31/3207.html […]
[…] 后面再网上找到了一篇文章讲解,这个问题的 http://www.laruence.com/2018/07/31/3207.html […]
这个问题是我经常问初中级的面试题
zi yi wei shi de sha bi mian shi guan
学习了
学习了,好文章,就喜欢这种干货!
这个 +1 month ,可以理解成 +30 day,这样就可以理解了为啥2017-08-31 变成了 2017-10-01
错了是 +31 day
就是月份加1不是加30天,再校验日期,请再熟读一边
2017-08-31加1月是 2017-09-31 进位了成2017-10-01
没有错,
相当于月位相加减,再格式化为合法的日期
学习了 期待更多好文
good
very helpful
$now = strtotime(“2018-03”);
echo date(‘Y-m-d’,strtotime(‘-1 month’, $now));
echo “\n”;
var_dump(date(‘Y-m-d’,strtotime(“first day of -1 month”,strtotime(“2018-03-31”))));
echo “\n”;
学到了
Nice
为什么要加first day , last day这种方式来手动规范结果而不是PHP语言自动将正确结果显示出来?我用PHP7的版本还是会有这种问题。
卧槽。。不敢用了。。这太坑了。。
emmm, 我一直都是01号开始+1 month,这种逻辑出现在金融上不堪设想
[…] 令人困惑的strtotime strtotime的一些问题 本条目发布于2019年5月12日。属于PHP分类,被贴了 php […]
[…] 本文地址: http://www.laruence.com/2018/07/31/3207.html […]
鸟哥,个人认为这个问题,不应该说是修正程序的问题吗?
如果 -1 month 溢出了,应该要取上个月真实的最后一天吧?
而不是没有这天,就直接把差值累加上去了。
您在这里说清楚了,但这个坑相信会被踩无数次,哈哈~
鸟哥,这个last day of -1 month,只能解决想获得的是所求日期的上个月月末最后一天,而并不能得到所求日期的一个月前的时间,说白了,一个月多久不定,php无法定义,
感觉如果真的想严谨的定义 -1 month 或者 +1month, 应该提供一个求上个月或者下个月天数n 的的函数,然后利用 -n days 或者 +n days 比较科学,因为一天24个小时,是固定不变的。。。
也就是这个 -1 month 不如自己写个方法,自己定义好12个月对应的天数n,然后利用 -n days 或者 +n days
dheaf http://wireless.fcc.gov/cgi-bin/wtbbye.pl?ftp://tidepool.nos.noaa.gov/pub/users/servary/pdt/rcs-capital-partners-help.pdf
以前竟然都没考虑过这种极端问题,隐藏的好深的bug
eee
我觉得这个问题应该这样理解,内部在实现的时候减去的为上个月所含有的天数。比如2月有29天 3月有31天
var_dump(date(“Y-m-d”, strtotime(“-1 month”, strtotime(“2017-03-31”))));得到的结果为2019-03-31减去的29天之后的日期。这样算是科学的,因为应该是从上月1号对应本月1号开始往后一一对应正推,而不是从本月底对应上月底来倒推。所以应该减去上月的天数。
笔误应该是var_dump(date(“Y-m-d”, strtotime(“-1 month”, strtotime(“2019-03-31”))));
test1
我测试过了好像的确是这样的,3月的30号减一个月就是03-02,29号就是03-01。
学到了
学到了
好,学到了
学好了
再学一次
111
11
1