Использование Carbon для создания нескольких дат с интервалом в диапазоне, но только в будущем

Мне нужно создать несколько дат между двумя датами на основе интервала (например, еженедельно, каждые 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;

Ожидаемые даты:

  • 2024-06-02
  • 2025-06-02
  • 2026-06-02
  • 2027-06-02

Хотя в данном случае это работает только в том случае, если я установлю дату окончания на 1 апреля 2029 года, что для меня не имеет смысла, поскольку последняя дата уже в 2027 году.

Используйте setEndDate(), чтобы установить дату окончания.

Olivier 17.03.2024 10:52

@Оливье, это вместо моего фильтра помогло. Не знаю, почему я об этом не подумал. Спасибо! Если бы вы могли написать ответ на этот вопрос, я бы отметил это как решение.

tinyoverflow 17.03.2024 22:05
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
2
164
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Синтаксис, который вы используете, мне кажется немного сложным, и если у вас с ним проблемы, возможно, подойдет что-то более простое. В документации показан довольно простой синтаксис 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. Комментарий Оливье отлично решил мою проблему с минимальными изменениями.

tinyoverflow 17.03.2024 22:19
Ответ принят как подходящий

Чтобы установить дату окончания, Carbon предоставляет метод setEndDate(), поэтому ваш код должен выглядеть следующим образом:

$period = CarbonPeriod::interval($interval)
    ->setStartDate($startDate)
    ->addFilter(fn(Carbon $carbon) => $carbon->isFuture(), 'isFuture')
    ->setEndDate($endDate)
    ->setRecurrences($amount);

Обратите внимание, что setEndDate() принимает значение null.

Другие вопросы по теме