skip to Main Content

I need to generate multiple dates between two dates, based on an interval (eg. weekly, every 2 weeks, monthly, …), but I only need the ones in the future.

For that I’m using the Carbon 2.72.3 library and I came up with the following code:

$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());

Unfortunately, this just works sometimes (meaning: Not with all dates / intervals) and I can’t tell exactly under what conditions it works and when it doesn’t work.

With the dates above, Carbon throws an CarbonExceptionsUnreachableException with the message Could not find next valid date.. If I reduce the amount to 1, it works, but only returns 2024-03-24 as a date (which is then expected, but doesn’t solve my issue).

With other data, such as this, it works as expected: It returns 4 dates according to the interval in relation to the start date, but only the ones in the future.

$interval = CarbonInterval::month();
$startDate = Carbon::create(2022, 6, 2);
$endDate = null;
$amount = 4;

If I set the $endDate = Carbon::create(2024, 4, 1);, it also stops working. I suspect that it sometimes happens when it cannot generate the $amount of dates. But this doesn’t seem to be the case always, as the following setup should be able to generate at least 4 dates, though the same exception is thrown:

$interval = CarbonInterval::year();
$startDate = Carbon::create(2022, 6, 2);
$endDate = Carbon::create(2028, 4, 1);
$amount = 4;

Expected dates:

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

Though in this case it only works if I set the end date to 2029-04-01, which doesn’t make sense to me as the last date is already in 2027.

2

Answers


  1. The syntax you’re using looks a bit complicated to me, and if you’re having trouble with it, maybe something simpler will work. The docs show pretty simple syntax for 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);
    

    And produces your expected output:

    [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
    
    Login or Signup to reply.
  2. To set the end date, Carbon provides the setEndDate() method, so your code should be like this:

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

    Note that setEndDate() accepts a null value.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search