Search code examples
phpdateincrementleap-year

Increment one month to date 2020-01-30 cancels the next month


Given date is 2019-12-30, and I want to add 1 month for every iteration in the loop (so 5 times).

I wrote this code:

$begin_date = '2019-12-30';
for ($i = 1; $i <= 5; $i++) {
    echo '<p>' . $begin_date . '</p>';

    $time = strtotime($begin_date);
    $begin_date = date("Y-m-d", strtotime("+1 month", $time));
}

And I got the following result

2019-12-30
2019-01-30
2019-03-01   invalid  --  I would expect 2019-02-28, at least last day
2019-04-01   invalid
2019-05-01   invalid

Solution

  • You can use DateTime objects, then modify the object to the last day of the next month. If the day of the month is greater than 30, subtract one (as it can never be higher than 31 anyways).

    $begin_date = '2019-12-30';
    $date = new DateTime($begin_date);
    for ($i = 1; $i <= 5; $i++) {
        echo '<p>'.$date->format("Y-m-d")."</p>\n";
        $date->modify("last day of next month");
        if ($date->format("d") > 30) {
            $date->modify("-1 day");
        }
    }
    

    If you're looking for a more dynamic way (in case the date is not always the 30th), you can duplicate the original object, and subtract the current day of month from the original day of the month.

    $begin_date = '2019-12-30';
    $date = new DateTime($begin_date);
    $original_date = clone $date;
    
    for ($i = 1; $i <= 5; $i++) {
        echo '<p>'.$date->format("Y-m-d")."</p>\n";
        $date->modify("last day of next month");
        if ($date->format("d") > $original_date->format("d")) {
            $date->modify("-".($date->format("d") - $original_date->format("d"))." day");
        }
    }