MENU

文章目录

    令人困惑的strtotime

    2018 年 11 月 26 日 • PHP阅读设置

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

    <?php
    //假设当前时间为2018-07-31
    echo 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

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

    <?php
    
    echo date("Y-m-d", strtotime("2017-06-31"));
    //输出2017-07-01

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

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

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

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

    那如果是5.3之前的版本(还有人用么?),可以使用mktime之类的,把所有的日子忽略掉,比如都限定为每月1号就可以了,只不过就不如直接用first day of 来的更加优雅。
    现在,搞清楚了内部原理,是不是就不慌了?

    返回文章列表 打赏
    本页链接的二维码
    打赏二维码