问题
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