Мне нужно создать несколько дат между двумя датами на основе интервала (например, еженедельно, каждые 2 недели, ежемесячно,...), но мне нужны только те, которые будут в будущем.
Для этого я использую библиотеку Carbon 2.72.3 и получил следующий код:
$interval = CarbonInterval::week();
$startDate = Carbon::create(2024, 3, 17);
$endDate = Carbon::create(2024, 4, 1);
$amount = 4;
$period = CarbonPeriod::interval($interval)
->setStartDate($startDate)
->addFilter(fn(Carbon $carbon) => $carbon->isFuture(), 'isFuture')
->addFilter(fn(Carbon $carbon) => !$endDate || $carbon->isBefore($endDate))
->setRecurrences($amount);
dd($period->toArray());
К сожалению, иногда это работает (то есть: не со всеми датами/интервалами), и я не могу точно сказать, при каких условиях это работает, а когда не работает.
Учитывая даты, указанные выше, Carbon ставит Carbon\Exceptions\UnreachableException вместе с сообщением Could not find next valid date.. Если я уменьшу сумму до 1, это сработает, но в качестве даты вернет только 24 марта 2024 г. (которая тогда ожидается, но не решает мою проблему).
С другими данными, такими как эти, он работает так, как ожидалось: возвращает 4 даты в соответствии с интервалом относительно начальной даты, но только те, которые находятся в будущем.
$interval = CarbonInterval::month();
$startDate = Carbon::create(2022, 6, 2);
$endDate = null;
$amount = 4;
Если я установлю $endDate = Carbon::create(2024, 4, 1);, он тоже перестанет работать. Я подозреваю, что это иногда случается, когда он не может сгенерировать $amount дат. Но, похоже, это не всегда так, поскольку следующая настройка должна иметь возможность генерировать как минимум 4 даты, хотя выдается одно и то же исключение:
$interval = CarbonInterval::year();
$startDate = Carbon::create(2022, 6, 2);
$endDate = Carbon::create(2028, 4, 1);
$amount = 4;
Ожидаемые даты:
Хотя в данном случае это работает только в том случае, если я установлю дату окончания на 1 апреля 2029 года, что для меня не имеет смысла, поскольку последняя дата уже в 2027 году.
@Оливье, это вместо моего фильтра помогло. Не знаю, почему я об этом не подумал. Спасибо! Если бы вы могли написать ответ на этот вопрос, я бы отметил это как решение.






Синтаксис, который вы используете, мне кажется немного сложным, и если у вас с ним проблемы, возможно, подойдет что-то более простое. В документации показан довольно простой синтаксис CarbonPeriod:
$startDate = '2022-06-02';
$endDate = '2028-04-01';
$interval = '1 year';
$number = 4;
$count = 0;
$results = [];
$period = new CarbonPeriod($startDate, $interval, $endDate);
foreach ($period as $date) {
if ($date->isPast()) {
continue;
}
$results[] = $date;
$count++;
if ($count >= $number) {
break;
}
}
print_r($results);
И выдает ожидаемый результат:
[date] => 2024-06-02 00:00:00.000000
[date] => 2025-06-02 00:00:00.000000
[date] => 2026-06-02 00:00:00.000000
[date] => 2027-06-02 00:00:00.000000
Спасибо! Лично я предпочитаю более «многословную» версию с использованием шаблона построения, предоставляемого классом CarbonPeriod. Комментарий Оливье отлично решил мою проблему с минимальными изменениями.
Чтобы установить дату окончания, Carbon предоставляет метод setEndDate(), поэтому ваш код должен выглядеть следующим образом:
$period = CarbonPeriod::interval($interval)
->setStartDate($startDate)
->addFilter(fn(Carbon $carbon) => $carbon->isFuture(), 'isFuture')
->setEndDate($endDate)
->setRecurrences($amount);
Обратите внимание, что setEndDate() принимает значение null.
Используйте
setEndDate(), чтобы установить дату окончания.