Percentage of hours calculation

4

How to calculate percentage between two schedules?

I tried it and it was not:

$tempo_total= "00:10:00";
$tempo_realizado= "00:05:00";

$percent= round((strtotime($tempo_realizado)/strtotime($tempo_total))*100);

It does not work.

    
asked by anonymous 04.11.2014 / 19:39

2 answers

8

In this case, I think you should convert the time to seconds and then do the calculation.

$tempo_total= "00:10:00";
$empo_realizado= "00:05:00";

$tt = time_to_sec($tempo_total);
$tr = time_to_sec($tempo_realizado);

$percent = round(($tr / $tt) * 100);

echo $percent;

function time_to_sec($time) {
    $hours = substr($time, 0, -6);
    $minutes = substr($time, -5, 2);
    $seconds = substr($time, -2);

    return $hours * 3600 + $minutes * 60 + $seconds;
}

By the tests I did here it worked, and in that case it returned 50 which I understood, would be 50% of the time.

    
04.11.2014 / 20:12
3

So far I've never experienced a case where using the right tool would be more complicated than using the wrong one.

Sounds like the story comes ...

For this type of calculation you should use the famous cross multiplication that we learned in elementary school:

A --- B
C --- D

In your case, these variables would represent:

  • A Total Time
  • B the percentage of Total Time (always 100)
  • C the Realized Time
  • D the value of the equation you need to find out

At these times the PHP elephant would be booming that since you're working with notions of time you should use the class DateTime , but a lot of calm at this time because it's not that easy, see:

$total      = "00:10:00";
$running    = "00:05:00";

$dt1 = DateTime::createFromFormat( 'H:i:s', $total   ) -> getTimestamp();
$dt2 = DateTime::createFromFormat( 'H:i:s', $running ) -> getTimestamp();

Common sense leads us to create DateTime objects from the time format H: i: s . And since we can not sensibly operate the hours, minutes and seconds, we get the timestamp of each of them to work with only seconds.

But when we apply these values in the mathematical formula:

$x = ( ( 100 * $dt2 ) / $dt1 );

We get 97.368421052632

What? o.

The implementation is correct, you can check in the calculator, but something is messing up the results and the culprit is not the butler, but the timezone .

The vast majority of PHP local installations have the date.timezone directive commented on or without a valid value, which causes any script to trigger the following Warning p>

  

It is not safe to rely on the system's timezone settings. You are required to use the date.timezone setting or the date_default_timezone_set () function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone.

And, to silence this error, as it guides itself, 99% of the time we start the script by invoking the date_default_timezone_set () to set a timezone . And it's just the use of this function that makes the cake go back.

When we create our DateTime objects and get timestamps , the returned integers take into account the timezone defined by the above function.

To solve this problem we have two alternatives:

  • Subtract the seconds obtained from the zero-seconds of the Era Unix , that is, January 1, 1970 at 00 : 00: 00
  • Explicitly define a timezone whose offset is zero
  • The first option is slightly more costly for the Application because it requires the creation of a third DateTime object:

    $start      = "00:00:00";
    $total      = "00:10:00";
    $running    = "00:05:00";
    
    $dt0 = DateTime::createFromFormat( 'H:i:s', $start   ) -> getTimestamp();
    $dt1 = DateTime::createFromFormat( 'H:i:s', $total   ) -> getTimestamp();
    $dt2 = DateTime::createFromFormat( 'H:i:s', $running ) -> getTimestamp();
    

    So we have to subtract from each of the two we already had:

    $x = ( ( 100 * ( $dt2 - $dt0 ) ) / ( $dt1 - $dt0 ) ); // 50
    

    The second option is more efficient, but not by any means obvious, for a change.

    DateTime :: createFromFormat () , as well as the class constructor DateTime , accepts a third argument, a DateTimeZone object. so that we can perform the operations with a offset other than the one generated by date_default_timezone_set ()

    It sounds simple, does not it? What is the difficulty of instantiating another object?

    $total      = "00:10:00";
    $running    = "00:05:00";
    
    $dt1 = DateTime::createFromFormat( 'H:i:s', $total,   new DateTimeZone( 'UTC' ) ) -> getTimestamp();
    $dt2 = DateTime::createFromFormat( 'H:i:s', $running, new DateTimeZone( 'UTC' ) ) -> getTimestamp();
    
    $x = ( ( 100 * $dt2 ) / $dt1 );
    

    But the result obtained ... 99.999978800777 .

    What? o.

    I'm still looking for more detailed and concrete information but what I have for the moment is that to work as expected we should create the DateTime using the complete notation (or at least date and time) of the Era Unix , that is, for your total time, 1970-01-01 00:10:00 :

    $dt1 = DateTime::createFromFormat( 'Y-m-d H:i:s', $total,   new DateTimeZone( 'UTC' ) ) -> getTimestamp();
    $dt2 = DateTime::createFromFormat( 'Y-m-d H:i:s', $running, new DateTimeZone( 'UTC' ) ) -> getTimestamp();
    
    $x = ( ( 100 * $dt2 ) / $dt1 ); // 50
    
        
    05.11.2014 / 14:30