1

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?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Rejoanul Alam
  • 5,435
  • 3
  • 39
  • 68
  • It is unclear what your problem is with "What I have tried is...." About the question: "Is it possible to use first iteration modified data into second iteration?". The answer is Yea, that should be possible. – Luuk Feb 26 '23 at 10:20
  • @Luuk I want to modify data in `0` index then use this modified data into `1` index – Rejoanul Alam Feb 26 '23 at 10:25
  • Yes, but it unclear why you failed at doing with "what you tried". should I guess that ? – Luuk Feb 26 '23 at 10:27
  • @Luuk What I have tried is not working. I need an idea how can I achieve the goal – Rejoanul Alam Feb 26 '23 at 10:28
  • Have you tried debugging this? (see: [How to debug PHP code](https://stackoverflow.com/questions/5710665/how-to-debug-php-code-under-linux-when-just-an-blank-page-is-shown), or any of the other pages on stackoverfflow.com which show ho to debug your PHP code?) – Luuk Feb 26 '23 at 10:32

2 Answers2

1

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

SelVazi
  • 10,028
  • 2
  • 13
  • 29
1

For a direct and concise way to create contiguous datetime stamps across all rows in your data, use a single loop, modify the rows by reference, declare a single datetime object, then bump or save the the datetime stamp as needed.

There is no need to waste/double memory by building a completely new output array.

Code: (Demo)

$format = 'Y-m-d H:i:s';
foreach ($jobs as &$row) {
    $dt ??= new DateTime($row['needed_at']);  // declare if not yet declared
    $row['needed_at'] = $dt->format($format); // save in desired format
    $dt->modify('+ 60 minutes');              // bump by duration in minutes
    $row['ended_at'] = $dt->format($format);  // save in desired format
    $dt->modify("+ {$row['add']} minutes");   // bump by gap in minutes in preparation for next row
}

var_export($jobs);
mickmackusa
  • 43,625
  • 12
  • 83
  • 136