Carbon Class: Always Remember to Use copy()

Unraveling the mystery of Carbon’s startOfDay() and endOfDay() functions – discover why they sometimes produce unexpected results and how to use them effectively for precise date and time manipulation.

Kode
Malacoturnix superciliosus Mountain Quail (1804-1902) print in high resolution by John Gould

Carbon is my favorite date manipulation class since the day one I introduced with Laravel. It simplifies working with dates and times, making tasks like date manipulation a breeze. However, there can be some confusion when using certain Carbon functions, like what I have been doing today.

The Problem

I wanted to manipulate using Carbon to get both the start and end of the day. Naturally, I reached for startOfDay() and endOfDay() functions, thinking they will do the job perfectly.

$dateCarbon = Carbon::parse($date);
$start = $dateCarbon->startOfDay(); // Outputs 2023-09-27 00:00:00
$end = $dateCarbon->endOfDay();     // Outputs 2023-09-27 00:00:00 (Expected: 2023-09-27 23:59:59)

Surprisingly, both $start and $end have the same value of 2023-09-27 00:00:00. This is not what I expected! The endOfDay() should give me the end of the day, which is typically 23:59:59.

The Explanation

The reason behind this behavior lies in how Carbon manages objects. When I call endOfDay() on a Carbon object, it modifies the same object instance and sets the time to midnight (00:00:00) of the same day. This happens because Carbon, by default, modifies the original object rather than creating a new one.

The Solution

After several searches and chats (with GPT), I found out that I need to make a copy of the Carbon object.

That was why my result always points the same value.

Here, I can tweak one instance for the start of the day and another for the end of the day without messing with the original date.

$dateCarbon = Carbon::parse($date);
$start = $dateCarbon->startOfDay();
$end = $dateCarbon->copy()->endOfDay(); // Now, $end will be 2023-09-27 23:59:59

By using $dateCarbon->copy() before calling endOfDay(), I ensure that I’m working with a separate instance of the Carbon object. This prevents unintended changes to the original date.