- 本文地址: https://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来的更加优雅.
现在, 搞清楚了内部原理, 是不是就不慌了? 🙂
Brother Bird actually updated it…
Very good post, thanks for the info
Thanks
echo date(‘Y-m-d H:i:s’,671565600);// 1991-04-14 03:00:00
echo strtotime(“1991-04-14 02:00:00”);//03
请问鸟哥,1991-04-14 02:00:00这个时间在某些php版本为什么会出现转换错误的情况
这么说也是哦,-1 month,每个月不一样的天数,所以正规是单纯地在月份上减去 1,很符合自然逻辑,哈哈。-1 月,实际上是减去上个月的天数,+1 月,实际上是加这个月的天数,这种逻辑很少人用吧。
[…] 本文转载自 https://www.laruence.com/2018/07/31/3207.html […]
这有点坑啊,以前都没发现,赶紧翻一翻代码
污泥螺杆泵
[…] 令人困惑的strtotime […]
[…] 参考: http://www.laruence.com/2018/07/31/3207.html […]
用carbon库就没这个问题了
`Carbon::parse(‘2019-12-31’)->subMonth();` 还是`2019-12-01`
可以使用 subMonthNoOverflow()
新手踩坑,前来膜拜
[…] 本文转载自: http://www.laruence.com/2018/07/31/3207.html […]
前几天,我走进大自然,没有来自城市的喧闹声,没有头痛,只有我和大自然的声音。
气动隔膜泵
正好用到这个,学习了。
确实很容易出现坑
不错支持一下
学习了
分享的不错
请教一下,如果想获取上周的周一,这种时间,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
niu bi
学习了
学习了,好文章,就喜欢这种干货!
这个 +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
了解了。
[…] 本文转载自: http://www.laruence.com/2018/07/31/3207.html […]
写的不错!
妙啊
很清楚 – what does it mean pls?
可是原本的需求还是没解决啊
好文 能学习
哥更文了!
[…] 本文地址: http://www.laruence.com/2018/07/31/3207.html […]
感觉这是WordPress的代码呢
恍然大悟啊
稳的一批
学习了
总结就是程序不会错,结果错说明用法不对
经常这样用,一直不理解,偶尔还出错,总算弄明白了,感谢博主。
暂时还没用到,先Mark一下
[…] 令人困惑的strtotime […]
[…] 参考资料:http://www.laruence.com/2018/… […]
[…] 令人困惑的strtotime […]
稳!
鸟哥分析的很清晰易懂
还是很慌怎么办….
既然正常人都觉得 10-31 的 *上一个月*不应该还是10月份,
那为什么不把默认值就设置为9月30号呢. 就算有短语可以修正,真的一点都不优雅, 而且很拗口=.=
漂亮
nice??
学习了
鸟哥。正文的字体太细了,能否改粗点
学习学习,涨知识
经常会有人被strtotime结合
还有这种操作,平时都没注意到。。。
学习了
[…] 令人困惑的strtotime […]
这个问题不应该用鸟哥最后讲的方法解决,还是应该在函数内部解决
之前遇到过这样的情况,也觉得strtotime不靠谱,但是没深究。感谢鸟哥,看来遇到问题最彻底的办法就是看源码?
涨姿势了,做项目一直都没注意到
鸟哥好棒
鸟哥好棒!
nice
1
2
00
000
只有我觉得右侧新浪添加关注的插件会挡住昵称而别扭嘛?!逼死强迫症。谷歌浏览器 版本 69.0.3497.100(正式版本) (64 位)
我这里也挡住了
不慌不慌
鸟哥好棒!
简单的问题复杂化,复杂的问题简单化!
通俗易懂,厉害厉害,我是转行过来做的php,现在会点python和golang,一入编程深似海,感觉学不完,随便哪个语言。。。
我刚刚百度完鸟哥的个人信息,好厉害,以后我们就叫你做大哥,你就叫我们练功夫
还是挺好理解的,官网文档看仔细点就不会乱了
学习了
好巧啊
一般获得「上个月的今天,当这天不存在就取上月的最后一天」,是更「亲人」的描述方式吧,这种逻辑就没办法很简单的一个 strtotime 去处理了。
讲的很清楚了~ 666
涨姿势了
还真不知道有这样操作,学习了。
向大佬学习,这以前还真不知道。哈哈
这是大佬时间长没写过业务了么? 为什么我搞清楚了反倒是感到这个函数好不靠谱? strtotime一点都不php风格,我现在有需求要求查询用户上个月的今天到今天一共做了某某个事件,请问怎么用一句strtotime解决???
取数据的时候,取这俩个时间的unix时间戳之间的对应的数据,count一下,不行嘛?
取数据的时候,取这俩个时间的unix时间戳之间的对应的数据,count一下,不行嘛?
echo date(“Y-m-d H:i:s”, strtotime(date(‘Y-m’)));
看下这个日期是不是你要的结果
慌而不乱
看完深覺 strtotime 的月份加減是雞肋了
沒辦法精準加減到上、下個月對應的日子
即使 first day of、last day of 也只能取得月初、月底
任意日期,也得另外判斷每個月有幾天
(正努力回想寫過的程式有沒用到功能過)
鸟哥终于换主题了! 特别像sublime的风格!
比如说我们是当前日期的上个月对应时间, 是个动态情况条件,那这个还是没有解决实际问题吧
自己转换一下呗,比如每个月都有10号,你就只用10号做’-1 month’操作,得到月份后再拼接一下日期。
你是一位出色的作家。 今天很难找到一个能清楚理解的人。谢谢! 我是你的常客。
赞
我司还在用5.2 #fml
都是7的时代了,你竟然还在用5.2?
作为PHP开发组为数不多的华人成员,私觉得鸟哥适合稍微提高一下发文频次,让我们这些“二把刀”能够对PHP有更深的了解。比如,PHP未来的发展方向、最新主版本(比如现在的PHP 7.3 Beta)在性能上的表现以及为什么。
模板比以前好看
解释得清晰明了!
第一个参数为时间戳时,在windows环境下,返回值一直正常。但是在linux环境下,有些时间戳返回正常,有些时间戳返回与预期不一样。(正常应该返回false),例如strtotime(1500516291)
感觉这个博客模板很low啊
鸟儿哥, 你终于终于换了个blog模板了
鸟哥
鸟哥大神,久仰您很久
仰望鸟哥,我这种PHP小菜鸟快完蛋了
鸟哥的博客主题终于换了。
更加慌了
恭喜鸟哥博客前端改版,看微博得知还是鸟哥亲自操刀。
哈哈哈,还是还以为谁博客呢。换主题了。差点没认出来。鸟哥加油永远支持php。
为什么不直接在php服务器里做判断 ,而是要用first day of 这个判断 ,每个月多少天是固定的
网站新的模版,好看多了!!
我在写js的时候也遇到过类似的问题,都是因为各个月份天数不同造成的。
怎能一个漂亮了得, 666
但我很害怕
我也有点慌了,鸟哥
哇,更新了,谢谢鸟哥
PHP 的时间函数和时区结合起来,感觉有点乱。特别是当语言自身,框架,ini 都可以配置时区的时候,就更加措手不及了。
还是很慌。。。为啥 first day of next month 取的不是0点的时间戳,而还是对应了当前时间的时分秒,大多数能够用到这个参数的需求是想取0点的时间戳。
谢谢
呃………这样啊
time()、date()、strtotime() 这三个函数的时区问题很烦~~
哇哦,博客换主题了,点个卯~
现在不慌了。
我也遇到过,幸好可以用mysql填这个坑
SELECT DATE_ADD( ‘2017-01-31’, INTERVAL 1 MONTH ),DATE_ADD( ‘2017-01-31’, INTERVAL 2 MONTH ),DATE_ADD( ‘2017-01-31’, INTERVAL 3 MONTH );
就可以得到和预期一样的结果
2017-02-28
2017-03-31
2017-04-30
http://lxjsmdc.com/php/get-next-month.html
终于更新了!
终于更新了!
额 其实还是很方啊,我一直以为是这样的,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-09-12)
鸟哥,请问下first day of/last day of后面的关键词,在底层是如何解析的?
使用first day of +1 month或者last day of +1 month,是可以获取到当前日期下个月的第一天或最后一天。
当如果我当前日期是2018-08-12,使用+1 month,会获取到2018-09-12,使用first day of +1 month,会得到2018-09-01。实际我是想获取到前者(2018-08-12),所以这个first day of还是有些情况不能兼容到
不慌了,原来如此
我现在更慌的…:(
感觉还是mktime好用,这种情况还是比较特殊的。不够灵活。
的确不慌了、
鸟哥终于更新博客了。
鸟哥竟然更新了…
最近是玩农药玩得少了呀,这可不行.再说dota2,马上ti了,训练不能少~!
谢谢鸟哥回复
匹配这么多种情况,还有这么长的字符串,我还是用mktime吧,啥时候给博客加上微博表情包就好了。
不慌,了
鸟哥更文了!