CarbonPeriod: 7 Examples of Date Time Lists For Reports and Calendars

CarbonPeriod: 7 Examples of Date Time Lists For Reports and Calendars
Admin
Saturday, July 15, 2023 9 mins to read
Share
CarbonPeriod: 7 Examples of Date Time Lists For Reports and Calendars

The Carbon class for dates and times is a part of Laravel by default, but there's also a less-known class, CarbonPeriod. It can help generate the ARRAY of datetimes, often useful for report tables and calendars. In this tutorial, let's look at the 7 most practical examples of CarbonPeriod.


Example 1. List of Hours Or Minute Intervals

What if you need an array list of working hours limited by start/end times?

  • 9:00
  • 10:00
  • 11:00
  • ...
  • 18:00

Look at this CarbonInterval snippet:

use Carbon\Carbon;
use Carbon\CarbonPeriod;
 
$startPeriod = Carbon::parse('9:00');
$endPeriod = Carbon::parse('18:00');
 
$period = CarbonPeriod::create($startPeriod, '1 hour', $endPeriod);
$hours = [];
 
foreach ($period as $date) {
$hours[] = $date->format('H:i');
}

Result:

array:10 [
0 => "09:00"
1 => "10:00"
2 => "11:00"
3 => "12:00"
4 => "13:00"
5 => "14:00"
6 => "15:00"
7 => "16:00"
8 => "17:00"
9 => "18:00"
]

As you can see, each CarbonPeriod element is a Carbon class instance that you can format however you want.

But it's not necessarily about the hours only. You can also change the period to smaller intervals, like "45 minutes":

$period = CarbonPeriod::create($startPeriod, '45 minutes', $endPeriod);

Result:

array:13 [
0 => "09:00"
1 => "09:45"
2 => "10:30"
3 => "11:15"
4 => "12:00"
5 => "12:45"
6 => "13:30"
7 => "14:15"
8 => "15:00"
9 => "15:45"
10 => "16:30"
11 => "17:15"
12 => "18:00"
]

You can also skip the first or last entry using the excludeStartDate or excludeEndDate methods.

$period = CarbonPeriod::create($startPeriod, '45 minutes', $endPeriod)
->excludeStartDate()
->excludeEndDate();
array:11
0 => "09:45"
1 => "10:30"
2 => "11:15"
3 => "12:00"
4 => "12:45"
5 => "13:30"
6 => "14:15"
7 => "15:00"
8 => "15:45"
9 => "16:30"
10 => "17:15"
]

Or change representation to a 12-hour format:

foreach ($period as $date) {
$hours[] = $date->format('h:i A');
}
array:11 [
0 => "09:45 AM"
1 => "10:30 AM"
2 => "11:15 AM"
3 => "12:00 PM"
4 => "12:45 PM"
5 => "01:30 PM"
6 => "02:15 PM"
7 => "03:00 PM"
8 => "03:45 PM"
9 => "04:30 PM"
10 => "05:15 PM"
]

Example 2. List of Dates By Weekdays

Let's say you want to schedule appointments, but have open slots only for Mondays and plan to do so for the current month.

use Carbon\CarbonPeriod;
 
$period = CarbonPeriod::between(now()->startOfMonth(), now()->endOfMonth())
->filter(fn ($date) => $date->isMonday());
$dates = [];
 
foreach ($period as $date) {
$dates[] = $date->format('M j, l, Y');
}

Result:

array:5 [
0 => "Jul 3, Monday, 2023"
1 => "Jul 10, Monday, 2023"
2 => "Jul 17, Monday, 2023"
3 => "Jul 24, Monday, 2023"
4 => "Jul 31, Monday, 2023"
]

As you can see, you can initialize the period with the ::between($start, $end) method and then add extra filters.

Of course, there are many more functions, not only ->isMonday().

Looking at the Carbon documentation, we can find these:

$dt->isWeekday();
$dt->isWeekend();
$dt->isTuesday();
// ...
$dt->isSunday();
 
$dt->isLastOfMonth();
$dt->isYesterday();
$dt->isToday();
$dt->isTomorrow();
$dt->isNextWeek();
$dt->isLastWeek();
 
// ... and more

Example 3. List of Weeks

What if you want to display a list of weeks as table columns? Each week has its number, so here's the example code for the week number with the start and end date of the week beginning on 2023-06-15 to 2023-07-15.

use Carbon\CarbonPeriod;
 
$period = CarbonPeriod::create('2023-06-15', '1 week', '2023-07-15');
$weeks = [];
$format = 'F j, Y';
 
foreach ($period as $date) {
$weeks[] = [
'week' => $date->format('W'),
'start' => $date->startOfWeek()->format($format),
'end' => $date->endOfWeek()->format($format),
];
}

Result:

array:5 [
0 => array:3 [
"week" => "24"
"start" => "June 12, 2023"
"end" => "June 18, 2023"
]
1 => array:3 [
"week" => "25"
"start" => "June 19, 2023"
"end" => "June 25, 2023"
]
2 => array:3 [
"week" => "26"
"start" => "June 26, 2023"
"end" => "July 2, 2023"
]
3 => array:3 [
"week" => "27"
"start" => "July 3, 2023"
"end" => "July 9, 2023"
]
4 => array:3 [
"week" => "28"
"start" => "July 10, 2023"
"end" => "July 16, 2023"
]
]

Example 4. List of Dates From Eloquent Model Column

Periods can be created from Model attributes when cast to Carbon instances. There's a shortcut method toPeriod() to make a CarbonPeriod instance.

For example, the recipient must pick up an order from the post office and choose a date. For this task, a person has five days to choose from, including the day it is delivered.

class Order extends Model
{
protected $fillable = ['shipped_at'];
 
protected $casts = [
'shipped_at' => 'date',
];
}
use App\Models\Order;
 
$order = Order::create(['shipped_at' => '2023-07-13']);
$period = $order->shipped_at
->toPeriod($order->shipped_at->copy()->addDays(5), '1 day')
->excludeEndDate();
$dates = [];
 
foreach ($period as $date) {
$dates[] = $date->format('Y-m-d');
}

Result:

array:5 [
0 => "2023-07-13"
1 => "2023-07-14"
2 => "2023-07-15"
3 => "2023-07-16"
4 => "2023-07-17"
]

But what if we want to skip weekends and have seven workdays to pick up orders? Three things to add here.

  1. We need to specify a later period end date, $order->shipped_at->addMonth().
  2. To have only seven entries from that period, the method setRecurrences() limits that.
  3. And finally, we filter() dates by weekdays.
use App\Models\Order;
 
$order = Order::create(['shipped_at' => '2023-07-13']);
$period = $order->shipped_at
->toPeriod($order->shipped_at->copy()->addMonth(), '1 day')
->setRecurrences(7)
->filter(fn ($date) => $date->isWeekday());
$dates = [];
 
foreach ($period as $date) {
$dates[] = $date->format('Y-m-d');
}

Result:

array:7 [ // test.php:18
0 => "2023-07-13"
1 => "2023-07-14"
2 => "2023-07-17"
3 => "2023-07-18"
4 => "2023-07-19"
5 => "2023-07-20"
6 => "2023-07-21"
]

Example 5. Find Period Overlaps

We have an employee list and know their vacation start and end dates. We need to list all employees who will have a vacation in the next 30 days so we can plan our tasks accordingly.

Our example dataset:

Employee::insert([
['name' => 'Helmer Wilkinson', 'vacation_start' => '2023-01-01', 'vacation_end' => '2023-02-01'],
['name' => 'Kaya Lowe', 'vacation_start' => '2023-07-05', 'vacation_end' => '2023-07-14'],
['name' => 'Royal Yundt', 'vacation_start' => '2023-07-20', 'vacation_end' => '2023-08-01'],
['name' => 'Willow Stark', 'vacation_start' => '2023-09-01', 'vacation_end' => '2023-09-15'],
]);

We can pass another period to the overlaps() method. It can also accept string values $period->overlaps('2023-06-23', '2023-07-04') and returns a boolean.

$startPeriod = Carbon::parse('2023-07-13');
$period = CarbonPeriod::create($startPeriod, $startPeriod->copy()->addMonth());
$onVacation = [];
 
Employee::get()->each(function ($user) use ($period, &$onVacation) {
$vacation = $user->vacation_start->toPeriod($user->vacation_end);
 
if ($vacation->overlaps($period)) {
$onVacation[] = $user->name;
}
});

Result:

array:2 [
0 => "Kaya Lowe"
1 => "Royal Yundt"
]

Example 6. Find If the Period Contains The Date

We can find out if a specific date falls into our period. For this example, let's say we want to list customers that have their birthday this month.

Customers dataset:

$customers = [
['name' => 'Helmer Wilkinson', 'birthday' => '1982-09-27'],
['name' => 'Kaya Lowe', 'birthday' => '1977-04-10'],
['name' => 'Royal Yundt', 'birthday' => '1975-03-30'],
['name' => 'Willow Stark', 'birthday' => '1988-07-27'],
['name' => 'Mortimer Vandervort', 'birthday' => '1982-04-03'],
['name' => 'Keven Morissette', 'birthday' => '1993-03-21'],
['name' => 'Pete Grant', 'birthday' => '1996-08-13'],
['name' => 'Kieran Schuster', 'birthday' => '1994-01-10'],
['name' => 'Rose Torphy', 'birthday' => '1988-04-23'],
['name' => 'Nyasia Senger', 'birthday' => '1993-07-06'],
];

Then we can use the contains() method on a period that returns a boolean.

use Carbon\Carbon;
use Carbon\CarbonPeriod;
 
$period = CarbonPeriod::create(now()->startOfMonth(), now()->endOfMonth());
 
$birthdaysThisMonth = [];
 
foreach ($customers as $customer) {
$born = Carbon::parse($customer['birthday']);
 
$birthdayThisYear = $born->copy()->year(now()->format('Y'));
 
if ($period->contains($birthdayThisYear)) {
$birthdaysThisMonth[] = sprintf(
'%s turns %d this month.',
$customer['name'],
$born->diffInYears($birthdayThisYear)
);
}
}

Given that the current month is July, this will be the result:

array:2 [
0 => "Willow Stark turns 35 this month."
1 => "Nyasia Senger turns 30 this month."
]

Example 7. Display Available Appointments For The Day

When a person chooses a certain date for an appointment, you can filter already booked times with the date. This example illustrates that:

use Carbon\Carbon;
use Carbon\CarbonPeriod;
 
$bookedAppointments = [
'2023-07-13 10:00',
'2023-07-13 14:00',
'2023-07-13 15:00',
];
 
$firstAppointment = Carbon::parse('2023-07-13 9:00');
$lastAppointment = Carbon::parse('2023-07-13 16:00');
$period = CarbonPeriod::create($firstAppointment, '1 hour', $lastAppointment)
->filter(function ($date) use ($bookedAppointments) {
return ! in_array($date->format('Y-m-d H:i'), $bookedAppointments);
});
 
$availableTimes = [];
 
foreach ($period as $date) {
$availableTimes[] = $date->format('Y-m-d H:i');
}

Result:

array:5 [
0 => "2023-07-13 09:00"
1 => "2023-07-13 11:00"
2 => "2023-07-13 12:00"
3 => "2023-07-13 13:00"
4 => "2023-07-13 16:00"
]

Want More About Date/Time?

So these are just a few examples of CarbonPeriod. If you want to dive a bit deeper into working date/time, we also have an interesting course: Laravel User Timezones Project: Convert, Display, Send Notifications