1

I have the total work hours saved in database as text like this: hhhhh:mm, for example a car has 789:07 in hours work (789 hours and 7 minutes). That work hours can be added or subtracted, what i do i split the string in hours and minutes and made the operation like this:

function addHours($initialTime, $endTime){
         $hourStart = $this->getHoursMinutes($initialTime);
         $hourEnd = $this->getHoursMinutes($endTime);

         $totalMinutes = $hourStart[1] + $hourEnd[1];

         $totalHours = 0;
         if($totalMinutes >= 60){
           $totalHours = 1;
           $totalMinutes -= 60;
         }

         $totalHours = $hourStart[0] + $hourEnd[0];

         return sprintf("%02d", $totalHours).":".sprintf("%02d", $totalMinutes);
       }

The substract method is:

function substractHours($initialTime, $endTime){
         $hourStart = $this->getHoursMinutes($initialTime);
         $hourEnd = $this->getHoursMinutes($endTime);


         $totalHours = $hourEnd[0] - $hourStart[0];

         $totalMinutes = $hourEnd[1] - $hourStart[1];
         if($totalMinutes <0){
           $totalMinutes += 60;
           $totalHours--;
         }

         return sprintf("%02d", $totalHours).":".sprintf("%02d", $totalMinutes);
       }

The methods works until I had to subtract two hours:

50:00 - 50:06

The result must be -00:06 (like excel function) but i got is -1:54 and i really doesn't know how to resolve this issue.

I though other way with PHP functions or example code in forums and posts but it works with 24:00 as maximum value.

Francisco
  • 10,918
  • 6
  • 34
  • 45
Juan Botero
  • 71
  • 1
  • 2
  • 12
  • 7
    Why not just store the minutes into your database and then calculate that way? e.g. 789:07 = 47347 minutes. Then it's simple math and conversion from minutes to hours: https://stackoverflow.com/questions/8563535/convert-number-of-minutes-into-hours-minutes-using-php – ctwheels Jun 28 '17 at 16:25
  • First convert hour:minutes to minutes and do adding or subtracting and convert back to hour:minutes. – Ravinder Reddy Jun 28 '17 at 16:32
  • Hi @Ctwheels. The fields already are stores as text hh:mm and really there's no option to change it, Thanks – Juan Botero Jun 29 '17 at 03:45
  • hi @RavinderI tried that but later it keep like: 00:-6 and that is really confusing, the hours and minutes keeps different. Thanks – Juan Botero Jun 29 '17 at 03:46
  • @JuanBotero ok, then just regex `(\d*):(\d*)` the numbers and convert the first capture group `$1` into minutes by multiplying by 60, then add the second capture group `$2`. Do the math on those values and convert back. The best approach, however, is just to store minutes in the database. Write a function to convert the value into minutes and put it into a new column of your table, then once you have all the rest of your code converted to use the new structure, change the name of the column to the old name and voila – ctwheels Jun 29 '17 at 13:38

3 Answers3

0

Your problem is occurring when the sign of the hours and the sign of the minutes are different, because you need to convert the minutes into hours. So you need to check for those situations and handle accordingly:

function substractHours($initialTime, $endTime){
  $hourStart = $this->getHoursMinutes($initialTime);
  $hourEnd = $this->getHoursMinutes($endTime);

  $totalHours = $hourEnd[0] - $hourStart[0];
  $totalMinutes = $hourEnd[1] - $hourStart[1];
  if($totalHours > 0 && $totalMinutes < 0) {
    $totalMinutes = 60 + $totalMinutes;
    $totalHours--;
  }
  else if ($totalHours < 0 && $totalMinutes > 0) {
    $totalMinutes = 60 - $totalMinutes;
    $totalHours++;
  }

  return sprintf("%02d", $totalHours).":".sprintf("%02d", $totalMinutes);
}

However, it's probably easier to just convert the hours into minutes, do the math and convert back.

$start = $hoursStart[0]*60 + $hoursStart[1];
$end = $hoursEnd[0]*60 + $hoursEnd[1];

// ... do math ...

$totalHours = floor(abs($total / 60));
$totalMinutes = abs($total) % 60;
$sign = $total < 0 ? "-" : "";
sorayadragon
  • 1,087
  • 7
  • 21
0

The best thing to do is to store it in the minimal unit, in this case minutes. Every operation will be easier. You should just convert to your final format when displaying this data.

Here is an example of a function to display your formatted time:

function
formattedTime($min): string
{
    $sign = $min < 0 ? '-' : '';
    $min  = abs($min);

    return sprintf('%s%02d:%02d', $sign, intdiv($min, 60), $min % 60);
}

Then you don't actually need functions to subtract or add times as you can use standard operators + or -. But if for some reason you can't change your data format or you must keep using those functions, then convert the passed time to minutes and operate on those. It is much simpler:

function
getMinutes($time): int
{
    $pieces;
    if (preg_match('/(\d+):(\d+)/', $time, $pieces))
        return $pieces[1]*60 + $pieces[2];

    return -1; # or throw Exception, i.e.
}

function
addHours($initialTime, $endTime)
{
    $initialTime = getMinutes($initialTime);
    $endTime     = getMinutes($endTime);

    return formattedTime($initialTime + $endTime);
}

function
subtractHours($initialTime, $endTime)
{
    $initialTime = getMinutes($initialTime);
    $endTime     = getMinutes($endTime);

    return formattedTime($initialTime - $endTime);
}
sidyll
  • 57,726
  • 14
  • 108
  • 151
0

There is no point storing both hours and minutes. Just stick to a single unit of time and use it throughout your application. Remember, the computer doesn't care about the distinction about minutes and hours, as far as the computer is concerned it's just a number. Only the user cares.

If you store both hours and minutes you have to do all the juggling you're trying to implement, but if you only store, for example, minutes, then summing up a running total of time becomes a simple addition, or even a SELECT SUM(column_name) query.

If the user does care about hours and minutes then you can do a simple conversion at display time using floor() and the modulus operator.

$hours = floor($total_minutes_as_fetched_from_database / 60);
$minutes = $total_minutes_as_fetched_from_database % 60;

echo "Total time is $hours hour(s) and $minutes minute(s)";
GordonM
  • 31,179
  • 15
  • 87
  • 129