Как гарантированно получить дату месяца из списка?

Мне нужно получить даты из прошлого основываясь на стартовой дате, которую указал пользователь. Например, если пользователь указал 05.12.2020, я должен получить все 5 числа до сегодняшней даты:

05.12.2020

05.01.2021

05.02.2021

05.03.2021

05.04.2021

05.05.2021

05.06.2021

Если пользователь указал 10.12.2020, я должен получить все 5 числа до сегодняшней даты:

05.12.2020

05.01.2021

05.02.2021

05.03.2021

05.04.2021

05.05.2021

09.06.2021 <<<

Код ниже выполняет данную задачу:

<?php

$begin = new DateTime( '05-12-2020' );
$end = new DateTime( date('d-m-Y') );
$end = $end->modify( '+31 day' ); //month

$interval = new DateInterval('P1M'); //31D
$daterange = new DatePeriod($begin, $interval ,$end);

foreach($daterange as $date){
    echo $date->format('d-m-Y') . '<br>' . PHP_EOL;
}

Но добавляет не существующую сегодня итоговую дату 05-07-2021

05-12-2020

05-01-2021

05-02-2021

05-03-2021

05-04-2021

05-05-2021

05-06-2021

05-07-2021

Если отредактировать строку $end = $end->modify( '+31 day' ); //month и поставить 20 дней, то код работает корректно, видимо это зависит от сегодняшней даты и в 20 числах он слетит.

Чтобы не путать вас, напишу то, что в итоге хочу получить.

Если пользователь указал дату 31.12.2019, мне нужен список месяцев с датами 31 и если в конкретном месяце нет 31 числа, то проставить последнюю дату данного месяца (26,27,28,29,30) но далее проставлять 31 числа. Если в текущем месяце 31 не наступило, проставить текущую дату.

Если сейчас в приведенном выше коде указать дату как 31 число, то даты сбиваются, так:

31-12-2020

31-01-2021

03-03-2021

03-04-2021

03-05-2021

03-06-2021

03-07-2021 <<<

Т.е. существует 2 проблемы:

1 конечный день месяца;

2 отображение в результате даты, которая еще не наступила.

Как реализовать?


Ответы (1 шт):

Автор решения: Jean-Claude

На основе этого ответа https://stackoverflow.com/questions/5760262/php-adding-months-to-a-date-while-not-exceeding-the-last-day-of-the-month

Суть в том, что если к 31 января 2021 года добавить 1 месяц, то будет не 28 февраля 2021, как предполагается логически, а 2 марта 2021, это и порождает проблемы.

Вот мой вариант вывода дат:

function add($date_str, $months) {

    $date = new DateTime($date_str);

    // We extract the day of the month as $start_day
    $start_day = $date->format('j');

    // We add 1 month to the given date
    $date->modify("+{$months} month");

    // We extract the day of the month again so we can compare
    $end_day = $date->format('j');

    if ($start_day != $end_day) {
        // The day of the month isn't the same anymore, so we correct the date
        $date->modify('last day of last month');
    }

    return $date;
}


function print_dates($date_str_begin) {

    $i = 0;
    $date_for_while = DateTime::createFromFormat('Y-m-d', $date_str_begin);

    while ($date_for_while->getTimestamp() < time()) {

        //прибавить месяц через функцию
        $date = add($date_str_begin, $i);
        //вывести на экран
        echo $date->format('Y-m-d') . '<br>';

        //тупо для завершения цикла
        $date_for_while->modify('+1 month');
        //для add()
        $i++;
    }
}

$date_str = '2020-12-31';
print_dates($date_str);

echo "\n\n<br>";

$date_str = '2020-12-05';
print_dates($date_str);

//2020-12-31
//2021-01-31
//2021-02-28
//2021-03-31
//2021-04-30
//2021-05-31
//
//2020-12-05
//2021-01-05
//2021-02-05
//2021-03-05
//2021-04-05
//2021-05-05
//2021-06-05
→ Ссылка