Calculate time interval in hours and minutes considering different days

Asked

Viewed 7,430 times

3

For now I have this code that is calculating the interval between the hours. I want to increment the calculation with minutes, and I want to make some changes in logic, for example when I put the input time as 23 hours and exit time as 12 hours of the other day, it returns me 11 hours, which should return 13.

<?php 
$hi = 23;
$hf = 12;
$total = -1;

$maior = calculaMaior($hi,$hf);
$menor = calculaMenor($hi,$hf);

for($i = $maior ; $i >= $menor ; $i--){
    $total++;
    echo"<br>$total<br>";//aqui ele irá mostrar todos os números só pra garantir
}
$aux = $maior + $total;
$total  = $aux - $total;
echo "<br>**************$total*************";

function calculaMaior($n1, $n2){
    if($n1 > $n2){
        return $n1;
    }else if($n1 < $n2){
        return $n2;
    }
}
function calculaMenor($n1, $n2){
    if($n1 > $n2){
        return $n2;
    }else if($n1 < $n2){
        return $n1;
    }
}
?>

2 answers

8


For periods of 24 hours or more, date should be used:

It is necessary to specify the date in these cases, for disambiguation.

PHP already has very efficient date functions to use in mathematical calculations, avoiding the use of date classes that are complex and inefficient for punctual things.

To convert a date into timestamp (which is numeric type) we have the:

gmmktime( hora, minuto, segundo, mes, dia, ano )

Care, as is PHP, of course the order of the parameters is meaningless. Note that the next month before the day.

See how to use:

<?php

    $entrada = gmmktime(  23, 30, 00, 05, 25, 2010 );
    $saida   = gmmktime(  11, 15, 00, 05, 26, 2010 );

    echo ( $saida - $entrada ) / 3600;

Note that you didn’t even need to create a function, it’s pure mathematics.

To format the output, it is very simple:

<?php

    $entrada = gmmktime(  23, 30, 00, 05, 25, 2010 );
    $saida   = gmmktime(  11, 15, 00, 05, 26, 2010 );
    $diferenca = abs( $saida - $entrada );

    printf( '%d:%d', $diferenca/3600, $diferenca/60%60 );

See working on PHP Sandbox.

  • The abs( ) serves to ignore the order of the dates, making the difference always positive. If the output is always higher, you can simplify with $diferenca = $saida - $entrada;.

  • the split is to transform the times into hours and minutes, as the timestamps are always expressed in seconds.

If you prefer to pass the dates by string is very similar:

<?php

    $entrada = strtotime( '2010-05-25 23:30' );
    $saida   = strtotime( '2010-05-26 11:15' );
    $diferenca = $saida - $entrada;

    printf( '%d:%d', $diferenca/3600, $diferenca/60%60 );

See working on PHP Sandbox.

Remembering that interpreting strings is usually less performatic than using separate numbers. It’s not as bad as instantiating a Datetime, but it’s already one more step.


For deadlines of less than 24 hours you can opt for basic math:

You did not specify how you will enter with the minutes, but anyway, I’m giving varied examples to give options:

<?php
    $entrada = '23:15';
    $saida   = '11:30';

    print_r( intervalo( $entrada, $saida ) );

    function intervalo( $entrada, $saida ) {
       $entrada = explode( ':', $entrada );
       $saida   = explode( ':', $saida );
       $minutos = ( $saida[0] - $entrada[0] ) * 60 + $saida[1] - $entrada[1];
       if( $minutos < 0 ) $minutos += 24 * 60;
       return sprintf( '%d:%d', $minutos / 60, $minutos % 60 );
    }

See working on PHP Sandbox.

With separate fields:

<?php
    $entradaH = 23;
    $entradaM = 15;
    $saidaH   = 11;
    $saidaM   = 30;

    print_r( intervalo( $entradaH, $entradaM, $saidaH, $saidaM ) );

    function intervalo( $entradaH, $entradaM, $saidaH, $saidaM ) {
       $minutos = ( $saidaH - $entradaH ) * 60 + $saidaM - $entradaM;
       if( $minutos < 0 ) $minutos += 24 * 60;
       return sprintf( '%d:%d', $minutos / 60, $minutos % 60 );
    }

See working on PHP Sandbox.

With Array:

<?php
    $entrada = array( 'h'=>23, 'm'=>15 );
    $saida   = array( 'h'=>11, 'm'=>30 );

    print_r( intervalo( $entrada, $saida ) );

    function intervalo( $entrada, $saida ) {
       $minutos = ( $saida['h'] - $entrada['h'] ) * 60 + $saida['m'] - $entrada['m'];
       if( $minutos < 0 ) $minutos += 24 * 60;
       return array( 'h'=>(int)( $minutos / 60), 'm'=>( $minutos % 60 ) );
    }

See working on IDEONE.


If you want to simplify by specifying the time in fractions, instead of 11:30 use 11.5 (eleven and a half), instead of 23:15 use 23.25 (twenty-three and a quarter):

<?php
    $entrada = 23.25;
    $saida   = 11.50;

    print_r( intervalo( $entrada, $saida ) );

    function intervalo( $entrada, $saida ) {
       $minutos = (int)($entrada * 60 - $saida * 60 );
       if( $minutos < 0 ) $minutos += 24 * 60;
       return $minutos / 60;
    }

See working on IDEONE.

This way you delegate formatting to a separate function to display in minutes and seconds on the screen, avoiding unnecessary conversions.

  • Both check if the departure time is shorter, and already make the adjustment for the next day.

  • This makes sense for deadlines of less than 24 hours. More than that, you need to specify date.

  • In case, I would like to take the time and the minute in different inputs, as I would do for me to join the two in order to do the calculations?

  • I added in the answer an option that accepts separate fields. Demonstration http://sandbox.onlinephpfunctions.com/code/ce07445b04778269a83542fe902cfa3808984169

  • okay, I’ll test

  • How could I do if I want to use the fields as arrays if I had more than one "client" ?

  • @Mickaelsouza has several ways, but if you make a loop calling the "interval" function, it already solves.

  • Okay, I’ll implement it this way

Show 1 more comment

2

Time calculation depends on date.

The routine you created does not consider the date, so returns the literal value 11.

Here’s a simulation of what you’re doing, but using the PHP native Datetime class:

// Create two new DateTime-objects...
$date1 = new DateTime('2016-08-28T23:00:00'); // pode definir sem a letra T, assim "2016-08-28 23:00:00". O importante é que tenha o formato ISO 8601
$date2 = new DateTime('2016-08-28T12:00:00');


// The diff-methods returns a new DateInterval-object...
$diff = $date2->diff($date1);

// Call the format method on the DateInterval-object
echo $diff->format('%a Day and %h hours');

From what I understand from the question, the 12:00 would be the next day, so it’s a date the next day:

// Create two new DateTime-objects...
$date1 = new DateTime('2016-08-28T23:00:00');
$date2 = new DateTime('2016-08-29T12:00:00');


// The diff-methods returns a new DateInterval-object...
$diff = $date2->diff($date1);

// Call the format method on the DateInterval-object
echo $diff->format('%a Day and %h hours');

The format above are didactic examples. For something more objective, test this:

$date1 = new DateTime('2016-08-28T23:00:00');
$date2 = new DateTime('2016-08-29T12:00:00');

$diff = $date2->diff($date1);

$hours = $diff->h;
$hours = $hours + ($diff->days*24);

echo $hours;

For more details:

Alternatively you can get the same result using functions such as strtotime(), gmmktime(), among others, but it makes no difference in performance. Both run in the same amount of time. A small difference is that the final memory consumption shows a difference of 1.3kb with Datetime, however at the peak of memory usage the difference is 400 bytes more for Datetime library.
Note that this time may vary according to the environment and was done without any optimization. The use of an opcache would render the difference null, for example.

The difference in this cost would be relevant if it performed in a massive long-term process and without any optimization running everything with reducers like crazy.

Finally, everything has a cost. You can choose to assemble all this by putting together a puzzle of old functions with parameters "without a friendly and logical pattern" and complain that PHP is bad (mimicry thing), or use a library that was created to fix this mess and bring more functionality.

Particularly, until a while ago I preferred to avoid Ibraries like Datetime, but I decided to arm myself and use these resources. They make development and maintenance much easier, as well as system flexibility.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.