How to get start and or end of year of a Carbon instance without modifying it in the process?
Asked Answered
J

4

15

Examine this self-explanatory code in PHP:

Reality:

$dateTime = Carbon::createFromDateTime(2017, 2, 23);

echo $dateTime; // 2017-02-23 00:00:00

echo $dateTime->startOfYear(); // 2017-12-31 23:59:59

echo $dateTime; // 2017-12-31 23:59:59

Notice that on the 4th line, the value of $dateTime is 2017-12-31 23:59:59. That is because on the 3rd line.

But why? I know that Carbon's startOfYear() is a modifier, but how can we therefore get a date's start of the year without modifying itself

Expected:

$dateTime = Carbon::createFromDateTime(2017, 2, 23);

echo $dateTime; // 2017-02-23 00:00:00

echo $dateTime->startOfYear(); // 2017-12-31 23:59:59

echo $dateTime; // 2017-02-23 00:00:00

Above, notice the 4th line. In reality, the 4th line outputs 2017-12-31 23:59:59.

Jena answered 23/2, 2017 at 3:29 Comment(3)
You are applying a modifier on the carbon instance. You need to cache it in some other variable first and do it there. This ensures your original one is safe. So $modifiedDate = $dateTime; $modifiedDate->startOfYear();Sumbawa
That would be costly thou. Doing so would require re-creating the same instance of the same date per operation: maybe get start of year on that date, then get end of month, start of month, start of day, end of day, etc. Aren't there any other more elegant way?Jena
Nice, checking on the answers below.Jena
T
34

Just like @SteD mentioned, you could use copy function to get existing instance and not modifying it.

$date = Carbon::createFromDate(2017, 2, 23);

$startOfYear = $date->copy()->startOfYear();
$endOfYear   = $date->copy()->endOfYear();
Tisiphone answered 23/2, 2017 at 3:41 Comment(1)
copy() is! Thanks!Jena
E
6

use copy()

From the docs

You can also create a copy() of an existing Carbon instance. As expected the date, time and timezone values are all copied to the new instance.

$dt = Carbon::now();
echo $dt->diffInYears($dt->copy()->addYear());  // 1

// $dt was unchanged and still holds the value of Carbon:now()
Eaton answered 23/2, 2017 at 3:37 Comment(4)
Good answer, but not sure if has any big advantage over creating a new variable?Sumbawa
You could, depends on your usage, at times you would just want to output it once and forget about it, so there's no need to create a new variable.Eaton
Thanks! copy() keeps the current value of the instance. This is what I needed exactly.Jena
@AliGajani, one advantage of copy is that you only have to have one instance of date, while allowing any amount of modification. Say you also want to get the endOfMonth, startOfMonth, etc of that date instance. Without copy(), or using variables, that would be 1 date instance per modification which would be bad.Jena
A
2

Late response - Carbon now supports an "immutable" version of their class, where endofYear() and similar modifiers return a new instance with the modified data, and the original object remains unchanged.

$date = CarbonImmutable::createFromDate(2017, 2, 23);

$startOfYear = $date->startOfYear(); // 2017-02-23 00:00:00
$endOfYear   = $date->endOfYear(); // 2017-12-31 23:59:59

more info here: https://medium.com/@jaketaylor_52917/how-to-use-carbon-2-0s-carbonimmutable-class-in-laravel-5-8-af7e794efbf7

Aeolis answered 11/1, 2022 at 10:28 Comment(0)
M
0

You're replacing the value of the $datetime variable in line 3. Effectively:

$a = 1;
echo $a;
$a = 2;
echo $a;

To fix this, you would need to do something like this:

$dateTime = Carbon::createFromDateTime(2017, 2, 23);

$startTime = $dateTime;

echo $dateTime->startOfYear();

Now you would have both dates. There may be more ways to skin the cat, but without knowing more about carbon, this is the simplest way to keep both.

Malynda answered 23/2, 2017 at 3:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.