PHP strtotime() +1 month / -1 month 和预期结果不符

想要使用 PHP 的 strtotime() 方法通过 +1 month / -1 month 获取下个月/上个月的年和月,遇到了和预期结果不符的问题。

观察下面的测试代码的输出结果发现问题原因:

public function actionTestDate()
{
    $startTime = '20180101';  // string
    $startTimeStamp = strtotime($startTime);  // stamp

    $endTime = '20180331';  // string
    $endTimeStamp = strtotime($endTime);  // stamp

    $result = [];
    for ($i = $startTimeStamp; $i <= $endTimeStamp; $i += 86400) {
        $iDate = date('Y-m-d H:i:s', $i); // date
        $iLastMonth = date('Y-m', strtotime('-1 month', $i));  // date
        $iNextMonth = date('Y-m', strtotime('+1 month', $i));  // date
        $result[] = $iDate . '----' . $iLastMonth . '----' . $iNextMonth;
    }

    return $result;
}

输出结果如下:

[
    "2018-01-01 00:00:00----2017-12----2018-02",
    "2018-01-02 00:00:00----2017-12----2018-02",
    "2018-01-03 00:00:00----2017-12----2018-02",
    "2018-01-04 00:00:00----2017-12----2018-02",
    "2018-01-05 00:00:00----2017-12----2018-02",
    "2018-01-06 00:00:00----2017-12----2018-02",
    "2018-01-07 00:00:00----2017-12----2018-02",
    "2018-01-08 00:00:00----2017-12----2018-02",
    "2018-01-09 00:00:00----2017-12----2018-02",
    "2018-01-10 00:00:00----2017-12----2018-02",
    "2018-01-11 00:00:00----2017-12----2018-02",
    "2018-01-12 00:00:00----2017-12----2018-02",
    "2018-01-13 00:00:00----2017-12----2018-02",
    "2018-01-14 00:00:00----2017-12----2018-02",
    "2018-01-15 00:00:00----2017-12----2018-02",
    "2018-01-16 00:00:00----2017-12----2018-02",
    "2018-01-17 00:00:00----2017-12----2018-02",
    "2018-01-18 00:00:00----2017-12----2018-02",
    "2018-01-19 00:00:00----2017-12----2018-02",
    "2018-01-20 00:00:00----2017-12----2018-02",
    "2018-01-21 00:00:00----2017-12----2018-02",
    "2018-01-22 00:00:00----2017-12----2018-02",
    "2018-01-23 00:00:00----2017-12----2018-02",
    "2018-01-24 00:00:00----2017-12----2018-02",
    "2018-01-25 00:00:00----2017-12----2018-02",
    "2018-01-26 00:00:00----2017-12----2018-02",
    "2018-01-27 00:00:00----2017-12----2018-02",
    "2018-01-28 00:00:00----2017-12----2018-02",
    "2018-01-29 00:00:00----2017-12----2018-03",
    "2018-01-30 00:00:00----2017-12----2018-03",
    "2018-01-31 00:00:00----2017-12----2018-03",
    "2018-02-01 00:00:00----2018-01----2018-03",
    "2018-02-02 00:00:00----2018-01----2018-03",
    "2018-02-03 00:00:00----2018-01----2018-03",
    "2018-02-04 00:00:00----2018-01----2018-03",
    "2018-02-05 00:00:00----2018-01----2018-03",
    "2018-02-06 00:00:00----2018-01----2018-03",
    "2018-02-07 00:00:00----2018-01----2018-03",
    "2018-02-08 00:00:00----2018-01----2018-03",
    "2018-02-09 00:00:00----2018-01----2018-03",
    "2018-02-10 00:00:00----2018-01----2018-03",
    "2018-02-11 00:00:00----2018-01----2018-03",
    "2018-02-12 00:00:00----2018-01----2018-03",
    "2018-02-13 00:00:00----2018-01----2018-03",
    "2018-02-14 00:00:00----2018-01----2018-03",
    "2018-02-15 00:00:00----2018-01----2018-03",
    "2018-02-16 00:00:00----2018-01----2018-03",
    "2018-02-17 00:00:00----2018-01----2018-03",
    "2018-02-18 00:00:00----2018-01----2018-03",
    "2018-02-19 00:00:00----2018-01----2018-03",
    "2018-02-20 00:00:00----2018-01----2018-03",
    "2018-02-21 00:00:00----2018-01----2018-03",
    "2018-02-22 00:00:00----2018-01----2018-03",
    "2018-02-23 00:00:00----2018-01----2018-03",
    "2018-02-24 00:00:00----2018-01----2018-03",
    "2018-02-25 00:00:00----2018-01----2018-03",
    "2018-02-26 00:00:00----2018-01----2018-03",
    "2018-02-27 00:00:00----2018-01----2018-03",
    "2018-02-28 00:00:00----2018-01----2018-03",
    "2018-03-01 00:00:00----2018-02----2018-04",
    "2018-03-02 00:00:00----2018-02----2018-04",
    "2018-03-03 00:00:00----2018-02----2018-04",
    "2018-03-04 00:00:00----2018-02----2018-04",
    "2018-03-05 00:00:00----2018-02----2018-04",
    "2018-03-06 00:00:00----2018-02----2018-04",
    "2018-03-07 00:00:00----2018-02----2018-04",
    "2018-03-08 00:00:00----2018-02----2018-04",
    "2018-03-09 00:00:00----2018-02----2018-04",
    "2018-03-10 00:00:00----2018-02----2018-04",
    "2018-03-11 00:00:00----2018-02----2018-04",
    "2018-03-12 00:00:00----2018-02----2018-04",
    "2018-03-13 00:00:00----2018-02----2018-04",
    "2018-03-14 00:00:00----2018-02----2018-04",
    "2018-03-15 00:00:00----2018-02----2018-04",
    "2018-03-16 00:00:00----2018-02----2018-04",
    "2018-03-17 00:00:00----2018-02----2018-04",
    "2018-03-18 00:00:00----2018-02----2018-04",
    "2018-03-19 00:00:00----2018-02----2018-04",
    "2018-03-20 00:00:00----2018-02----2018-04",
    "2018-03-21 00:00:00----2018-02----2018-04",
    "2018-03-22 00:00:00----2018-02----2018-04",
    "2018-03-23 00:00:00----2018-02----2018-04",
    "2018-03-24 00:00:00----2018-02----2018-04",
    "2018-03-25 00:00:00----2018-02----2018-04",
    "2018-03-26 00:00:00----2018-02----2018-04",
    "2018-03-27 00:00:00----2018-02----2018-04",
    "2018-03-28 00:00:00----2018-02----2018-04",
    "2018-03-29 00:00:00----2018-03----2018-04",
    "2018-03-30 00:00:00----2018-03----2018-04",
    "2018-03-31 00:00:00----2018-03----2018-05"
]

从输出结果分析发现:

2018 年 2 月份有 28 天,那么 2018 年 1 月份中 28 日 之后的日期的下个月是不符合预期的(2018-01-29、2018-01-30、2018-01-31);

2018 年 2 月份有 28 天,那么 2018 年 3 月份中 28 日 之后的日期的上个月是不符合预期的(2018-03-29、2018-03-30、2018-03-31);

......

结论: 本月天数大于上月天数或本月天数大于下月天数均会出现类似问题。伪代码如下:

if (本月天数 > 下月天数) {
    本月的最后 (本月天数 - 下月天数) 的下月日期不符合预期;
}
举例:
本月为 1 月, 31 天;下月为 2 月, 28 天;1 月的最后 3 天的下月日期不符合预期;



if (本月天数 > 上月天数) {
    本月的最后 (本月天数 - 上月天数) 的上月日期不符合预期;
}
举例:
本月为 3 月, 31 天;上月为 2 月, 28 天;3 月的最后 3 天的上月日期不符合预期;

解决方案:

先获取到本月的第一天,然后进行 +1 month、-1 month 的操作。

public function actionTestDate()
{
    $startTime = '20180101';  // string
    $startTimeStamp = strtotime($startTime);  // stamp

    $endTime = '20180331';  // string
    $endTimeStamp = strtotime($endTime);  // stamp

    $result = [];
    for ($i = $startTimeStamp; $i <= $endTimeStamp; $i += 86400) {
        $iDate = date('Y-m-d H:i:s', $i); // date
        $iFirstDay = date('Y-m-01', $i); // date
        $iLastMonth = date('Y-m', strtotime('-1 month', strtotime($iFirstDay)));  // date
        $iNextMonth = date('Y-m', strtotime('+1 month', strtotime($iFirstDay)));  // date
        $result[] = $iDate . '----' . $iLastMonth . '----' . $iNextMonth;
    }

    return $result;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值