Search code examples
phparraysphp-carbonarray-map

Why is carbon addMinutes doing bad addition


In Laravel environment I have a set of times that I am adding minutes to and it is not giving me what I expect.

In the below array_map function there is some weird addMinutes happening

$d = array_map(function ($date) {
    $base = Carbon::parse($date['time']);
    return [
        'start' => $base->addMinutes(150)->toDateTimeString(),
        'end' => $base->addMinutes(190)->toDateTimeString()
    ]
}, $dates);

So 150mins is 2hrs30mins, 190mins is 3hrs10mins, so I would assume the following

2018-07-05 19.20.00 (+150 mins) -> start = 2018-07-05 21.50
                    (+190 mins) -> end   = 2018-07-05 22.30

I am actually getting

2018-07-05 19.20.00 (+150 mins) -> start = 2018-07-05 21.30
                    (+190 mins) -> end   = 2018-07-06 00.40

Can anyone see the obvious I'm missing here with the Carbon processing ? I'm quite certain it has to do with Carbon as I restructured the above array_map into a foreach and same results with the same addMinutes.

Edit:

I've just adapted this code for anyone to help diagnose by pasting the below into phpio

require 'Carbon/Carbon.php';
use Carbon\Carbon;

$dates[] = ['time' => '2018-07-05 19:20:00'];

$d = array_map(function ($date) {
    $base = Carbon::parse($date['time']);
    return [
        'start' => $base->addMinutes(150)->toDateTimeString(),
        'end' => $base->addMinutes(190)->toDateTimeString()
    ];
}, $dates);

print_r($d);

WEIRD - now the start is correct, but end is still incorrect (showing 2018-07-06 01:00:00)


Solution

  • Take a look at this code:

    return [
        'start' => $base->addMinutes(150)->toDateTimeString(),
        'end' => $base->addMinutes(190)->toDateTimeString()
    ]
    

    In both situations, you're adding to $base, so you're adding 150 minutes, then an additional 190 (so a total of 340 minutes). Try using with ->copy():

    return [
        'start' => $base->copy()->addMinutes(150)->toDateTimeString(),
        'end' => $base->copy()->addMinutes(190)->toDateTimeString()
    ]
    

    Using the following code in phpio:

    require 'Carbon/Carbon.php';
    use Carbon\Carbon;
    
    $dates[] = ['time' => '2018-07-05 19:20:00'];
    
    $d = array_map(function ($date) {
      $base = Carbon::parse($date['time']);
      return [
        'start' => $base->copy()->addMinutes(150)->toDateTimeString(),
        'end' => $base->copy()->addMinutes(190)->toDateTimeString()
      ];
    }, $dates);
    
    print_r($d);
    

    Gives me the following:

    Array ( [0] => Array ( [start] => 2018-07-05 21:50:00 [end] => 2018-07-05 22:30:00 ) )