phparraysdatetimemultidimensional-arraycontiguous

Modify rows in a 2d array so that datetime stamps are contiguous


I have a 2d array of jobs and each job contains a start time, an end time which is always 60 minutes after the start time, then an "add" value which is the number of minutes until the next job should start.

I need to adjust all rows so that each start time is the previous job's end time plus its "add" time.

Here is a sample array:

[
    [
        'id' => 9,
        'needed_at' => '2023-02-26 03:31:04',
        'ended_at' => '2023-02-26 04:31:04',
        'add' => 20
    ],
    [
        'id' => 6,
        'needed_at' => '2023-02-26 04:51:04',
        'ended_at' => '2023-02-26 05:51:04',
        'add' => 30
    ],
    [
        'id' => 7,
        'needed_at' => '2023-02-26 09:21:04',
        'ended_at' => '2023-02-26 10:21:04',
        'add' => 30
    ]
]

My desired result:

[
    [
        'id' => 9,
        'needed_at' => '2023-02-26 03:31:04',
        'ended_at' => '2023-02-26 04:31:04',
        'add' => 20
    ],
    [
        'id' => 6,
        'needed_at' => '2023-02-26 04:51:04',
        'ended_at' => '2023-02-26 05:51:04',
        'add' => 30
    ],
    [
        'id' => 7,
        'needed_at' => '2023-02-26 06:21:04',  # changed based on id 6 data
        'ended_at' => '2023-02-26 07:21:04',   # changed based on new need_at time of this row
        'add' => 30                            # not actually used because no next job
    ]
]

What I have tried is:

foreach ($jobs as $k => $j) {
    $s = $k+1;
    $date = new \DateTimeImmutable($j->ended_at);
    $add = $j->add;
    $date_new = $date->modify('+'.$add.' minutes');
    $needed_at = $date_new->format('Y-m-d H:i:s');
    $data['needed_at'] = $needed_at;
    
    $date2 = new \DateTimeImmutable($needed_at);
    $ended_at = $date2->modify('+60 minutes');
    $data['ended_at'] = $ended_at->format('Y-m-d H:i:s');
    $d[]=[
        'id' => $jobs[$s]->id,
        'needed_at' => $needed_at,
        'ended_at' => $data['ended_at'],
        'add' => $add
    ];
}

It is not working. Is it possible to use first iteration modified data into second iteration?


Solution

  • Since the first element of the array will not change we excluded from the loop.

    Two elements are important to get the expected output : ended_at and add, then after each iteration those variables will take the current values and so on

    $format = 'Y-m-d H:i:s';
    
    $ended_at = $jobs[0]['ended_at'];
    $add = $jobs[0]['add'];
    
    $d[0] = $jobs[0];
    foreach($jobs as $k => $j){
           if ($k < 1) continue;
           
           $ended_at = DateTimeImmutable::createFromFormat($format, $ended_at);
           
           $ended = $ended_at->modify('+'.$add.' minutes');
           $needed = $ended->modify('+60 minutes');
           
           $ended = $ended->format($format);
           $needed = $needed->format($format);
           
           $d[]=array(
             'id' => $jobs[$k]['id'],
             'needed_at' => $ended,
             'ended_at' => $needed,
             'add' => $jobs[$k]['add']
           );
           
           $ended_at = $needed;
           $add = $jobs[$k]['add'];
           
    }
    
    print_r($d);
    

    Demo here