Friday, 10 August 2018

Converting To And From Decimal Time In PHP

To convert a time value into a decimal value representing the number of minutes can be useful for certain calculations. The following function takes a time as a string of hh:mm:ss and returns a decimal value in minutes.
  1. /**
  2.  * Convert time into decimal time.
  3.  *
  4.  * @param string $time The time to convert
  5.  *
  6.  * @return integer The time as a decimal value.
  7.  */
  8. function time_to_decimal($time) {
  9. $timeArr = explode(':', $time);
  10. $decTime = ($timeArr[0]*60) + ($timeArr[1]) + ($timeArr[2]/60);
  11.  
  12. return $decTime;
  13. }
If we take the time of 11:11:11 this gets split into 3 parts by the explode() function into hours, minutes and seconds, which then gets treated in the following way:
  1. Minutes = (Hours x 60) + (Minutes) + (Seconds / 60)
  2. Minutes = (11 x 60) + (11) + (11 / 60)
  3. Minutes = (660) + (11) + (0.18333333)
  4. Minutes = 671.18333333
The function can be used as follows:
  1. echo time_to_decimal("11:11:11"); // prints 671.18333333
The reverse of this function takes the decimal value and returns a string in the format hh:mm:ss.
  1. /**
  2.  * Convert decimal time into time in the format hh:mm:ss
  3.  *
  4.  * @param integer The time as a decimal value.
  5.  *
  6.  * @return string $time The converted time value.
  7.  */
  8. function decimal_to_time($decimal) {
  9. $hours = floor($decimal / 60);
  10. $minutes = floor($decimal % / 60);
  11. $seconds = $decimal - (int)$decimal;
  12. $seconds = round($seconds * 60);
  13.  
  14. return str_pad($hours, 2, "0", STR_PAD_LEFT) . ":" . str_pad($minutes, 2, "0", STR_PAD_LEFT) . ":" . str_pad($seconds, 2, "0", STR_PAD_LEFT);
  15. }
This function can be used as follows:
  1. echo decimal_to_time(671.18333333); // prints 11:11:11
Note that these functions deal with amounts of time, not the time of day. Converting between time and decimal time of day requires a different set of calculations.
UPDATE: Thanks to an anonymous poster for pointing out some errors, these have now been corrected.
Your code indeed works in the manner you have described, however there are a couple of finer details that caused issues for me when using the code.
In the time_to_decimal function, line 12 should read as follows:
$decTime = ($timeArr[0]*60) + ($timeArr[1]) + ($timeArr[2]/60);
As it is written in your post, the seconds are actually representing fractions of an hour (1/3600th) as opposed to fractions of a minute (1/60th). 
We have the same issue in the decimal_to_time function as well as an issue in regards to the round() function.  I've corrected the decimal_to_time function as follows:
  1. function decimal_to_time($decimal) {
  2. $hours = floor((int)$decimal / 60);
  3. $minutes = floor((int)$decimal % 60);
  4. $seconds = $decimal - (int)$decimal;
  5. $seconds = round($seconds * 60);
  6.  
  7. return str_pad($hours, 2, "0", STR_PAD_LEFT) . ":" . str_pad($minutes, 2, "0", STR_PAD_LEFT) . ":" . str_pad($seconds, 2, "0", STR_PAD_LEFT);
  8. }
round() in lines 2 and 3 have been replaced by floor().  This is due to the behavior of round() returning 1 when given .5.  An example is as follows:
Say we are converting 1:30:30 into a decimal representing minutes.  Using the two functions posted we would have
  1. echo time_to_decimal('1:30:30'); // prints 90.008333333333, seconds are still converted incorrectly
  2.  
  3. // this should display the input from the first function
  4. echo decimal_to_time(90.008333333333); // prints 02:02:30, not correct
In the example, line 2 of the original code calculates to - round( 90 / 60 ) = round(1.5) = 2.  Since we only want the numer of whole hours in the $decimal variable, we should use floor() instead.  floor() will always round to the lowest whole number ( 1 in this case )
I hope this helps someone out there :)
i propose to change little to allow this kind of input "01:05" =1h05 or "01:05:00" or "01"=1hour
  1. function time_to_decimal($time) {
  2. $timeArr = explode(':', $time);
  3. if (count($timeArr) == 3) {
  4. $decTime = ($timeArr[0]*60) + ($timeArr[1]) + ($timeArr[2]/60);
  5. } else if (count($timeArr) == 2) {
  6. $decTime = ($timeArr[0]) + ($timeArr[1]/60);
  7. } else if (count($timeArr) == 2) {
  8. $decTime = $time;
  9. }
  10. return $decTime;
  11. }
This function kept returning :60 in the seconds place! I added :
  1. if ($seconds == 60) {
  2. $minutes++;
  3. $seconds=0;
  4. }
to the end of the function.
My 2 cents comment if used your function and added a format control to avoid strange behavior and surprise
  1. function Time_To_Decimal($time) {
  2. $decTime = 0;
  3. if (preg_match("/^([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/", $time, $matches)) {
  4. $decTime = ($matches[0]*60) + ($matches[1]) + ($matches[2]/60);
  5. }
  6. return $decTime;
  7. }
Sorry posted too quickly (fixed preg_match return array)
  1. function Time_To_Decimal($time) {
  2. $decTime = 0;
  3. if (preg_match("/^([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/", $time, $matches)) {
  4. $decTime = ($matches[1]*60) + ($matches[2]) + ($matches[3]/60);
  5. }
  6. return $decTime;
  7. }

0 comments:

Post a Comment