PHP Carbon class changing my original variable value
Asked Answered
M

3

65

I'm trying to make a few navigation buttons in a calendar type thing I'm creating, and I'm using carbon to create the dates.

This is the code in the controller:

if ($date == null) {
    $date = \Carbon\Carbon::now();
} else {
    $date = \Carbon\Carbon::createFromFormat('Y-m-d', $date);
}
$navDays = [
    '-7Days' => $date->subDay('7')->toDateString(),
    '-1Day'  => $date->subDay('1')->toDateString(),
    'Today'    => $date->today()->toDateString(),
    '+1Day'  => $date->addDay('1')->toDateString(),
    '+7Days' => $date->addDay('7')->toDateString()
];

and then I'm my view, I'm doing this:

@foreach($navDays as $key => $i)
    <li>
        <a href="/planner/bookings/{{ $i }}" class="small button">
            {{ $key }}
        </a>
    </li>
@endforeach

This problem is, that carbon seems to change the $date during the array creating, because these are the dates I'm getting(with $date being set to 2015-11-29):

<ul class="button-group even-5">
    <li><a href="/planner/bookings/2015-11-22" class="small button">-7Days</a></li>
    <li><a href="/planner/bookings/2015-11-21" class="small button">-1Day</a></li>
    <li><a href="/planner/bookings/2015-12-22" class="small button">Today</a></li>
    <li><a href="/planner/bookings/2015-11-22" class="small button">+1Day</a></li>
    <li><a href="/planner/bookings/2015-11-29" class="small button">+7Days</a></li>
</ul>

Does anybody know what I'm doing wrong?

Meyerhof answered 22/12, 2015 at 10:39 Comment(0)
C
129

When you run these methods against a Carbon object it updates the object itself. Therefore addDay() moves the value of Carbon one day forward.

Here's what you need to do:

$now = Carbon::now();

$now->copy()->addDay();
$now->copy()->addMonth();
$now->copy()->addYear();
// etc...

The copy method essentially creates a new Carbon object which you can then apply the changes to without affecting the original $now variable.

To sum up, the methods for copying a Carbon instance are:

  • copy
  • clone - an alias of copy

Check out the documentation: https://carbon.nesbot.com/docs/

Comras answered 18/4, 2018 at 17:37 Comment(2)
As of Laravel +5.8 you can also do $now->toImmutable()->addDay().Shingly
@AmirHossein you should add this as a full answer. It's a much cleaner method to work with immutable objects instead of cloning a mutable one.Unreasonable
M
17

The problem is that you're assuming that subDay()/addDay() don't change the date object, whereas they do.... they're just wrapping around the DateTime object modify() method:

DateTime::modify -- date_modify — Alters the timestamp

(my emphasis)

Instead, use

$navDays = [
    '-7Days' => (clone $date)->subDay('7')->toDateString(),
    '-1Day'  => (clone $date)->subDay('1')->toDateString(),
    'Today'  => (clone $date)->today()->toDateString(),
    '+1Day'  => (clone $date)->addDay('1')->toDateString(),
    '+7Days' => (clone $date)->addDay('7')->toDateString()
];
Millian answered 22/12, 2015 at 10:47 Comment(4)
this gives me an error: syntax error, unexpected '->' (T_OBJECT_OPERATOR), expecting ']' Do i need to set these before hand, and then add them to the array?Chrischrism
Sorry, realised that I'd tested while in my php7 environment and didn't think that it wouldn't work with PHP5Millian
carbon also has a copy method so you can do something like.. $date->copy()->subDay('7')->toDateString()Amie
php.net/manual/en/class.datetime.php vs php.net/manual/en/class.datetimeimmutable.php. Carbon is based on the firstMaidie
D
3

Doco says

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()
Degenerate answered 1/1, 2019 at 23:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.