'How to subtract time from time array using php?

Hello seniors I have a question related to some PHP script.

I have an array containing time => ['12:10', '4:16', '2:5'] and have one html form containing input field of type 'number'.

I want when I enter some value in my form input field for example I enter 7, so after submitting the form in back-end the number 7 which i enter in input field is subtracted from the array which I mentioned above and I will get the result array like: ['5:10', '4:16', '2:5']

I have tried something like that but not able to implement my logic

$val = array(1, 0, 2, 1, 1);
    $subtract = 3.5;
    foreach ($val as $key => $item) {
        if ($subtract >= $item) {
            $subtract -= $item;
            $val[$key] = 0;
        } else {
            $val[$key] -= $subtract;
            $subtract = 0;
        }
    }

Any kind of help is highly appreciated



Solution 1:[1]

You can use Carbon library for date/time manipulation:

<?php
use Carbon\Carbon;

$times = ['17:46', '03:05', '21:56'];
$timeshift = 3;

$new_times = array_map(
    fn($t) => Carbon::createFromFormat('H:i',  $t)
                ->subHours($timeshift)
                ->format('H:i'),
    $times
);

Test Carbon library online

Solution 2:[2]

No need for library, just convert your first array to seconds: 1 hour = 3600 ; 1 minute = 60 ; 12:10 is 12 x 3600 + 10 x 60, then you do the same thing to your $_POST value, then use gmdate() to retrieve the original format of your array

  $myTimes=array('12:10', '4:16', '2:5');
  //do the math 
  $splittedTime = explode(":", $myTimes[0]); //in your case
  $timeInSeconds = $splittedTime[0] * 3600 + $splittedTime[1] * 60 ;
  //do the same thing to your your $_POST value if needed or simply 
  $totalReduceby = 7 * 3600;
   // get new total of seconds
  $newTime= $timeInSeconds - $totalReduceby;
  $result = ltrim(gmdate("H:i", $newTime),0); //ltrim to remove the leading 0
  $myTimes=array($result, '4:16', '2:5');
  //print_r($myTimes);

Solution 3:[3]

time => ['12:10', '4:16', '2:5'] [...] the number 7 which i enter in input field is subtracted from the array I will get the result array like: ['5:10', '4:16', '2:5']

Your example is a little ambiguous. Do you only want to subtract the field value from the first element of the array, always? Or only from those elements which are greater than the submitted value?

It's pretty straightforward to subtract minutes from a mm:ss time string; simplest is probably to generalize so that the amount to subtract is also allowed to be mm:ss instead of always being a whole number of minutes. I would just explode both of them, turn them into total seconds (minutes*60+seconds), subtract those, and then turn back into mm:ss. Both conversions might be worth their own functions:

function mmssToSeconds($timeStr) {
   if (str_contains($timeStr, ':')) {
      list($min, $sec) = explode(':', $timeStr);
   } else {
      list($min, $sec) = array($timeStr, 0);
   }
   if ($min < 0) {
     return 60*$min - $sec;
   } else {
     return 60*$min + $sec;
   }
}

function secondsToMmss($seconds) {
   $abs = abs($seconds);
   $sgn = $seconds / $abs;
   $min = floor($abs / 60);
   $sec = $abs % 60;
   return ($sgn < 0 ? '-' : '').sprintf('%d:%02d', $min, $sec);
}

And then the subtraction is easy:

function subtractMinutes($from, $delta) {
   return secondsToMmss(mmssToSeconds($from) - mmssToSeconds($delta));
}

If you want to subtract from each element that is big enough, you could use a loop like this:

foreach ($ary['time'] as $i => $t) {
  if ((int)$t > $subtract) {
    $ary['time'][$i] = subtractMinutes($t, $subtract);
  }
}

The comparison works because the cast from string to int ignores everything after the first non-digit, so '12:10' just becomes 12, which is > 7.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Slava Rozhnev
Solution 2
Solution 3