Calculate time interval in hours and minutes considering different days [duplicate]

this question already has answers here : subtraction of hours in php (5 responses) Closed there 4 years .

For now I have this code that is calculating the interval between hours. I want to increment the calculation with minutes, and I want to make some changes to the logic, for example when I put the input time as 23 hours and output time as 12 hours the other day, it returns me 11 hours, and it 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
Author: Bacco, 2016-08-28

2 answers

For deadlines of 24 hours or more, you should use date:

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 point things.

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

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

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

Here's 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 have to create a function, it's pure math.

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 larger, you can simplify with $diferenca = $saida - $entrada;.

  • A division is to turn times into hours and minutes, as the timestamps are always expressed in seconds.

If you prefer to pass the dates by string it 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 performative than using separate numbers. It's not as bad as instantiating a DateTime, but it's already a step a more.


for deadlines of less than 24 hours you can opt for even basic mathematics:

You did not specify how you will enter with the minutes, but anyway, tou 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 fractional, 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 exit time is smaller, 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.

 8
Author: Bacco, 2016-08-28 20:30:48

Time calculation depends on the date.

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

Here is a simulation of what you are doing, but using the dateTime class, native to PHP:

// 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 my understanding of the question, 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 above format 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 reach the same result using functions like 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 has a difference of 1.3 kb with DateTime, in the however, at peak memory usage the difference is 400 bytes more for Library DateTime.
Note that this time may vary depending on the environment and was done without any optimization. Using an opcache would make the difference null, for example.

The difference in this cost would be relevant if it ran in a massive process of long duration and without any Optimization running everything with reductions made a fool.

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

Particularly, until a while ago I preferred to avoid libraries like DateTime, but I decided to give the arm a twist and use these features. They greatly facilitate development and maintenance, as well as system flexibility.

 1
Author: Daniel Omine, 2016-08-28 17:00:23