PHP Carbon, get all dates between date range?
Asked Answered
A

11

104

How can I get all dates between two dates in PHP? Prefer using Carbon for dates.

$from = Carbon::now();
$to = Carbon::createFromDate(2017, 5, 21);

I wanna have all dates between those two dates.. But how? Can only found solutions using strtotime function.

Anal answered 6/8, 2015 at 7:24 Comment(0)
P
212

As of Carbon 1.29 it is possible to do:

$period = CarbonPeriod::create('2018-06-14', '2018-06-20');

// Iterate over the period
foreach ($period as $date) {
    echo $date->format('Y-m-d');
}

// Convert the period to an array of dates
$dates = $period->toArray();

See documentation for more details: https://carbon.nesbot.com/docs/#api-period.

Professionalize answered 14/6, 2018 at 9:52 Comment(3)
Just a friendly remember, you can also use $date->toDateString() to get date as format Y-m-d. Docs.Guatemala
@ibnɘꟻ I'm aware of it, but the ->format() gives you the ability to globally store the string format in config. So, whenever there is a request to change the format everywhere, you don't need to change the code everywhere.Nonferrous
Also you can use ->ceilYears() example $period = CarbonPeriod::create('2020-06-06', '2028-06-06')->ceilYears() Period will return only array of yearsFlopeared
Z
77

Here's how I did it with Carbon

private function generateDateRange(Carbon $start_date, Carbon $end_date)
{
    $dates = [];

    for($date = $start_date->copy(); $date->lte($end_date); $date->addDay()) {
        $dates[] = $date->format('Y-m-d');
    }

    return $dates;
}
Zinn answered 26/1, 2016 at 18:25 Comment(1)
Won't you have the problem of $start_date being equal to $end_date in the end? If you want to continue using the original $start_date after this function is called, you should either pass a copy of the original $start_date to this function or set $date = $start_date -> copy() in the definition of the for-loop, which I would prefer.Cacciatore
S
22

As Carbon is an extension of PHP's built-in DateTime, you should be able to use DatePeriod and DateInterval, exactly as you would with a DateTime object

$interval = new DateInterval('P1D');
$to->add($interval);
$daterange = new DatePeriod($from, $interval ,$to);

foreach($daterange as $date){
    echo $date->format("Ymd"), PHP_EOL;
}

EDIT

If you need to include the final date of the period, then you need to modify it slightly, and adjust $to before generating the DatePeriod

$interval = new DateInterval('P1D');
$daterange = new DatePeriod($from, $interval ,$to);

foreach($daterange as $date){
    echo $date->format("Ymd"), PHP_EOL;
}
Scapolite answered 6/8, 2015 at 7:32 Comment(2)
This does not print last date from the interval if $to time is not bigger. I mean at least on second has to be bigger, maybe milisecond, did not try thatLiturgist
Added relevant line of code to include the $to date in the periodScapolite
A
11

Based on Mark Baker's answer, I wrote this function:

/**
 * Compute a range between two dates, and generate
 * a plain array of Carbon objects of each day in it.
 *
 * @param  \Carbon\Carbon  $from
 * @param  \Carbon\Carbon  $to
 * @param  bool  $inclusive
 * @return array|null
 *
 * @author Tristan Jahier
 */
function date_range(Carbon\Carbon $from, Carbon\Carbon $to, $inclusive = true)
{
    if ($from->gt($to)) {
        return null;
    }

    // Clone the date objects to avoid issues, then reset their time
    $from = $from->copy()->startOfDay();
    $to = $to->copy()->startOfDay();

    // Include the end date in the range
    if ($inclusive) {
        $to->addDay();
    }

    $step = Carbon\CarbonInterval::day();
    $period = new DatePeriod($from, $step, $to);

    // Convert the DatePeriod into a plain array of Carbon objects
    $range = [];

    foreach ($period as $day) {
        $range[] = new Carbon\Carbon($day);
    }

    return ! empty($range) ? $range : null;
}

Usage:

>>> date_range(Carbon::parse('2016-07-21'), Carbon::parse('2016-07-23'));
=> [
     Carbon\Carbon {#760
       +"date": "2016-07-21 00:00:00.000000",
       +"timezone_type": 3,
       +"timezone": "UTC",
     },
     Carbon\Carbon {#759
       +"date": "2016-07-22 00:00:00.000000",
       +"timezone_type": 3,
       +"timezone": "UTC",
     },
     Carbon\Carbon {#761
       +"date": "2016-07-23 00:00:00.000000",
       +"timezone_type": 3,
       +"timezone": "UTC",
     },
   ]

You can also pass a boolean (false) as third argument to exclude the end date.

Ash answered 22/7, 2016 at 20:14 Comment(0)
W
6

This can also be done like this:

new DatePeriod($startDate, new DateInterval('P1D'), $endDate)

Just keep in mind that DatePeriod is an iterator, so if you want an actual array:

iterator_to_array(new DatePeriod($startDate, new DateInterval('P1D'), $endDate))

If you're using Laravel, you could always create a Carbon macro:

Carbon::macro('range', function ($start, $end) {
    return new Collection(new DatePeriod($start, new DateInterval('P1D'), $end));
});

Now you can do this:

foreach (Carbon::range($start, $end) as $date) {
   // ...
}
Woolfolk answered 25/11, 2017 at 12:18 Comment(0)
L
5

Here is what I have:

private function getDatesFromRange($date_time_from, $date_time_to)
    {

        // cut hours, because not getting last day when hours of time to is less than hours of time_from
        // see while loop
        $start = Carbon::createFromFormat('Y-m-d', substr($date_time_from, 0, 10));
        $end = Carbon::createFromFormat('Y-m-d', substr($date_time_to, 0, 10));

        $dates = [];

        while ($start->lte($end)) {

            $dates[] = $start->copy()->format('Y-m-d');

            $start->addDay();
        }

        return $dates;
    }

Example:

$this->getDatesFromRange('2015-03-15 10:10:10', '2015-03-19 09:10:10');
Liturgist answered 10/9, 2015 at 11:37 Comment(0)
P
2

You can't use loop control variable directly, the next must be work fine

$start = Carbon::today()->startOfWeek();
$end = Carbon::today()->endOfWeek();

$stack = [];

$date = $start;
while ($date <= $end) {

    if (! $date->isWeekend()) {
        $stack[] = $date->copy();
    }
    $date->addDays(1);
}

return $stack;
Perquisite answered 16/10, 2017 at 20:25 Comment(0)
G
2

You can directly using Carbon

    $start = Carbon::createFromDate(2017, 5, 21);
    $end = Carbon::now();

    while($start < $end){
        echo $start->format("M");
        $start->addMonth();
    }
Gisarme answered 1/10, 2018 at 22:45 Comment(0)
D
-1

I think it's will be better if you use this function

 public static function check_continuous_dates(array $dates): bool
    {
        $startDate = Carbon::create($dates[0]);
        $endDate = Carbon::create(end($dates));
        if ($endDate->diffInDays($startDate)+1 == count($dates)) {
            return true;
        }
        return false;
    } 
Daisy answered 30/11, 2022 at 17:0 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Carlson
E
-2
//To get just an array of dates, follow this.


        $period = CarbonPeriod::create('2018-06-14', '2018-06-20');

        $p = array();
    // If you want just dates
    // Iterate over the period and create push to array
        foreach ($period as $date) {
            $p[] = $date->format('Y-m-d');
        }

    // Return an array of dates

        return $p;
Electrodeposit answered 13/6, 2019 at 4:50 Comment(1)
Please add description to your answer, so anyone can understand what's your code algorithm. Don't spoonfeeding.Guatemala
F
-3

Very simple solution (it works with old "<1.29" carbon ) :

// set $start and $end to any date
$start = Carbon::now()->addDays(-10);
$end = Carbon::now();

$dates = [];
for($i = 0; $i < $end->diffInDays($start); $i++){
    $dates[] = (clone $start)->addDays($i)->format('Y-m-d');
}
dd($dates);
Foxtrot answered 1/5, 2020 at 9:42 Comment(2)
Amazingly slow solutionAnal
fastest solution is obviously with CarbonPeriod but it is a relative new Caarbon feature and many app can not use that, my solutions covers older carbon version and is the same fast as solution from @Sebastien ...I measured it just now......Foxtrot

© 2022 - 2024 — McMap. All rights reserved.