Monthly recurring event on specific date and skip any month if have less no of days compare to user's selected date

有些话、适合烂在心里 提交于 2021-01-28 07:41:16

问题


I am creating a app where user can create monthly event (Just like Google/Outlook), so if user has selected 31st date of any month and next month have 30 days than all next dates are changing to 30th.

Same goes with 30th, lets say user selected 30th of December than after Feb all next date is changing to 28th.

so if in next month days are lesser than user's selected date its changing the date to that.

Example : Start Date : 2020-10-31 End Date : 2021-11-30

$diffInMonths = $startDate->diffInMonths($endDate);
for ($i = 0; $i <= $diffInMonths; $i++) {
    $newStartDate = $i == 0 ? $startDate : $startDate->addMonthWithNoOverflow();
    print('<pre>' . print_r($newStartDate->toDateString(), true) . '</pre>');
}

its giving output like this

2020-10-31
2020-11-30
2020-12-30
2021-01-30
2021-02-28
2021-03-28
2021-04-28
2021-05-28
2021-06-28
2021-07-28
2021-08-28
2021-09-28
2021-10-28

What i need is skip the month if in that month have less days than user;s selected date. With Above example the correct output should be

2020-10-31 //November has less than 31st day
2020-12-31
2021-01-31 //Feb has less than 31st day
2021-03-31 //April has less than 31st day
2021-05-31 //June & July has less than 31st day
2021-07-31 
2021-08-31 //September has less than 31st day
2021-10-31

Struggling on this from last 2-3 days so any Kind of help or guidance will made my day :)


回答1:


This might be dumb way of doing this, but as i am running out of time so here is solution

$dateRange = Carbon::parse($callPlanner->start_date)->toPeriod($callPlanner->end_date, 1, 'month');
        $startDate = Carbon::parse($callPlanner->start_date);

        foreach ($dateRange as $date) {
            // compare the event date with end of month date
            if ($startDate->day <= $date->endOfMonth()->day) {
                //create new date with this month's year, month and event start date
                $newDate = Carbon::createFromDate($date->endOfMonth()->year, $date->endOfMonth()->month, $startDate->day);
                echo $newDate->toDateString(). "\n";
            }
        }



回答2:


addMonths() add a month to a date. with no overflow, it makes the end of the next month, which is suppose 2020-02-29. in the next step it adds another month to 2020-02-29 and that makes the next date 2020-03-29 because it just added a month. you don't call it to update the date. so your solution would be using lastOfMonth()

$startDate = Carbon::parse('2020-01-31');
$endDate = Carbon::parse('2020-12-31');
$diffInMonths = $startDate->diffInMonths($endDate);
for ($i = 0; $i <= $diffInMonths; $i++) {
    $newStartDate = $i == 0 ? $startDate : $startDate->addMonthWithNoOverflow()->lastOfMonth();
    print('<pre>' . print_r($newStartDate->toDateString(), true) . '</pre>');
}

which will give you dates like

2020-01-31
2020-02-29
2020-03-31
2020-04-30
2020-05-31
2020-06-30
2020-07-31
2020-08-31
2020-09-30
2020-10-31
2020-11-30
2020-12-31

with addMonth you can't skip months that has less days. you have to check it manually with some condition. like

$startDate = Carbon::parse('2020-10-31');
$endDate = Carbon::parse('2021-11-30');
$highestDate = $startDate->format('d');
$diffInMonths = $startDate->diffInMonths($endDate);
for ($i = 0; $i <= $diffInMonths; $i++) {
    $newStartDate = $i == 0 ? $startDate : $startDate->addMonthWithNoOverflow()->lastOfMonth();
    if ($newStartDate->format('d') >= $highestDate) {
        print('<pre>' . print_r($newStartDate->toDateString(), true) . '</pre>');
    } 
}

the output is

2020-10-31
2020-12-31
2021-01-31
2021-03-31
2021-05-31
2021-07-31
2021-08-31
2021-10-31



回答3:


In such cases (similar to monthly subscriptions issues), it could be better to always start from the first date instead of chaining the additions:

$diffInMonths = $startDate->diffInMonths($endDate);
for ($i = 0; $i <= $diffInMonths; $i++) {
    $newStartDate = $startDate->copy()->addMonthsWithNoOverflow($i + 1);
    print('<pre>' . print_r($newStartDate->toDateString(), true) . '</pre>');
}

This way, you get last day of month is the day is not available but it does not change next iterations.

Note that ->copy() is not needed if you use CarbonImmutable.



来源:https://stackoverflow.com/questions/64424925/monthly-recurring-event-on-specific-date-and-skip-any-month-if-have-less-no-of-d

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!