62

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?

Lakhwinder Singh
  • 5,536
  • 5
  • 27
  • 52
Johan Björklund
  • 726
  • 2
  • 7
  • 16

3 Answers3

120

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/

Denialos
  • 956
  • 7
  • 16
diggersworld
  • 12,770
  • 24
  • 84
  • 119
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()
];
Mark Baker
  • 209,507
  • 32
  • 346
  • 385
  • 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? – Johan Björklund Dec 22 '15 at 13:29
  • Sorry, realised that I'd tested while in my php7 environment and didn't think that it wouldn't work with PHP5 – Mark Baker Dec 22 '15 at 13:38
  • 16
    carbon also has a copy method so you can do something like.. $date->copy()->subDay('7')->toDateString() – nrivero Dec 22 '15 at 14:04
  • http://php.net/manual/en/class.datetime.php vs http://php.net/manual/en/class.datetimeimmutable.php. Carbon is based on the first – challet Apr 16 '18 at 14:17
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()
Yevgeniy Afanasyev
  • 37,872
  • 26
  • 173
  • 191