2

I want to calculate difference of two times and print it in pretty way. I know the difference will never exceed 24 hours, so I tried the following

$time = 7200; //time difference in seconds
date("H:i:s", $time); // should print 02:00

The result is unexpected, it prints 03:00 instead.

What am I doing wrong?

Samuel Hapak
  • 6,950
  • 3
  • 35
  • 58
  • 1
    plenty of different good examples here http://stackoverflow.com/questions/676824/how-to-calculate-the-difference-between-two-dates-using-php – Markedagain Jul 20 '12 at 14:58

3 Answers3

2

Why not the DateTime::diff??

Here, check PHP.net for DateTime class

Grabbed from php.net datetime diff page:

$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-13');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%a days');

//Outputs +2 days
João Dias
  • 1,078
  • 1
  • 15
  • 38
  • Sometimes you just know the number of seconds and you do not have two dates, you want to subtract. For example, how long would it take to wash a dishes, if you wash a plate in 48 seconds and you have 148 plates. – Samuel Hapak Jul 20 '12 at 15:37
  • That thoughts weren't on the question... that's a math problem. If you want to solve problems like that, just write your own function instead! I think it's better. For "calculate difference of two times" I find this approach to be a lot simpler and safer than using timestamps! – João Dias Jul 20 '12 at 15:54
  • Yes, between two dates. But assume you have work-shift and you want to compute total working time of that shift. Shift starts at `timeStart`, ends at `timeEnd` and there is lunch pause between `$lunchStart` and `$lunchEnd`. You cannot simply compute this using `DateTime::diff`. – Samuel Hapak Jul 21 '12 at 07:55
  • Yes you can! Do math! timeEnd-timeStart - lunchTime! Or timeEnd -(lunchTime-timeStart)... I'm not trying to prove a point here though. Obviously, this has its own limitations. What I'm trying to say is that you should adjust your programming tools to its purposes. – João Dias Jul 23 '12 at 00:03
1

You should never use date to compute time difference. Firstly it is ugly hack. It was not intended for that purpose. And secondly, it works reliably only when timezone set to UTC.

Now, why it does not work: PHP function date takes two arguments, format and timestamp, the latter is defined as number of seconds from 1st January 1970 00:00 UTC called unix epoch. So if you call date("H:i", 3600) and your timezone is set to UTC, it will return "01:00", cause it represents time one hour after unix epoch and the epoch was at the midnight.

The problem is, unix epoch was at the midnight only in UTC, not in the other timezones. And this is the source of the incorrect result.

Samuel Hapak
  • 6,950
  • 3
  • 35
  • 58
  • 1
    The true underlying problem is not setting the correct timezone with `date_default_timezone_set`. – nickb Jul 20 '12 at 14:57
  • 1
    Did you answer your own question? – Pitchinnate Jul 20 '12 at 14:59
  • 1
    @Pitchinnate: He did, and it's fine – Madara's Ghost Jul 20 '12 at 15:01
  • 1
    @nickb: No, the underlying problem is trying to use `date()` for something it was never meant to do. Setting the time zone to UTC is just a hack to make it sort of work, at least for a limited range of time deltas. – Ilmari Karonen Jul 20 '12 at 15:01
  • @Ilmari - I never said it was the correct / best implementation. The reason for the discrepancy of expected output vs. actual output is because of the wrong timezone. That's all - Don't read too far into it. – nickb Jul 20 '12 at 15:04
1

The PHP date() function is meant for formatting absolute time stamps (as in "Friday, 20 July 2012, 15:02 UTC"), not for time differences (as in "3 hours and 5 minutes ago").

In some cases, it is possible to trick date() into producing something that looks like a correctly formatted time difference by setting your time zone to UTC and relying on the fact that the Unix epoch happens to fall on midnight in UTC. However, even then, this will only work for positive time differences of less than 24 hours.

Instead, the correct solution is to use a function designed for formatting time differences, or write one yourself. Here's a simple function to do so:

function format_time_difference ( $delta ) {
    $sign = ( $delta < 0 ? "-" : "" );
    $delta = abs( $delta );
    return sprintf( "%s%02d:%02d:%02d", $sign, $delta / 3600,
                    ($delta / 60) % 60, $delta % 60 ); 
}

Of course, you can extend this function to e.g. include days in the output if you like.

Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153