开发者

Issue finding difference between two times. (PHP/MySQL)

I am trying to identify the duration of something by finding the difference between the start time and the end time.

//bring date & time input into mysql datetime format for query

$t_start_datetime = date('Y-m-d G:i:s' ,strtotime($_POST['t_date'].' '.$_POST['t_start'].' '.$_POST['s_ampm']));
$t_end_datetime = date('Y-m-d G:i:s' ,strtotime($_POST['t_date'].' '.$_POST['t_end'].' '.$_POST['e_ampm']));

// get duration value of test by finding the difference between the start and end time.
$end_time= strtotime($_POST['t_date'].' '.$_POST['t_start'].' '.$_POST['s_ampm']);
$start_time= strtotime($_POST['t_date'].' '.$_POST['t_end'].' '.$_POST['e_ampm']);

$temp = $end_time - $start_time;

echo date('G:i:s', $end_time);
echo date('G:i:s', $start_time);
//here is the duration
echo date('G:i开发者_StackOverflow中文版:s', abs($temp));

So lets say the value of start_time was 6:00:00 and end_time 7:45:00 my duration is coming out as 2:45:00 :S

It's always an hour more than the actually difference.

What am I doing wrong? Please enlighten me.

Thanks


The problem

First, consider this:

<?php
echo date('Y-m-d H:i:s', 300); // Output for GMT: "1970-01-01 00:05:00"
?>

The UNIX timestamp is 300 seconds (or 5 minutes) after the UNIX epoch. date() displays this time in your current, local timezone.

Now consider this:

<?php
echo date('Y-m-d H:i:s', 18000); // Output for GMT: "1970-01-01 05:00:00"
?>

This is 5 hours after the UNIX epoch. But recall that date() uses your current local timezone, so if you're in, say, British Summer Time (GMT+1), you get:

<?php
date_default_timezone_set("Etc/GMT+1"); // Setting manually for demonstration
echo date('Y-m-d H:i:s', 18000); // Output for BST: "1970-01-01 04:00:00"
?>

Even though it wasn't BST on the 1st Jan 1970, it's BST now and that's the timezone being used for the date's display.

But you didn't really mean to talk about dates in 1970... you just wanted to format a duration. The duration was five hours, but you're getting four hours back.

A solution

You can hack around this using the variant gmdate(), which always uses GMT:

<?php
date_default_timezone_set("Etc/GMT+1"); // Setting manually for demonstration
echo gmdate('Y-m-d H:i:s', 18000); // Output always: "1970-01-01 05:00:00"
?>

You could also avoid limited UNIX timestamps altogether, by using PHP's object-oriented DateTime class:

<?php
$d = new DateTime('@18000');
echo $d->format('G:i:s'); // Output always: 05:00:00
?>

In context

Now consider your own code. After your calls to strtotime, $temp is a UNIX timestamp like the dates I use in my examples above. The same issue applies when you then use date().

With gmdate():

$start_time = strtotime($_POST['t_date'].' '.$_POST['t_end'].' '.$_POST['e_ampm']);
$end_time   = strtotime($_POST['t_date'].' '.$_POST['t_start'].' '.$_POST['s_ampm']);

$temp = $end_time - $start_time;
echo gmdate('H:i:s', $temp);

With DateTime:

$start_time = strtotime($_POST['t_date'].' '.$_POST['t_end'].' '.$_POST['e_ampm']);
$end_time   = strtotime($_POST['t_date'].' '.$_POST['t_start'].' '.$_POST['s_ampm']);

$temp = $end_time - $start_time;
$temp = new DateTime('@' . $temp);
echo $temp->format('H:i:s');

Hope that helps.


$end_time   = new DateTime($_POST['t_date'].' '.$_POST['t_send'].' '.$_POST['s_ampm']);
$start_time = new DateTime($_POST['t_date'].' '.$_POST['t_start'].' '.$_POST['e_ampm']);
$diff       = $end_time->diff($start_time);
echo $diff->format('%H:%I:%S');

You cannot use the regular date formatting here as it'll treat $temp as a UNIX timestamp and will therefore be influenced by timezones and issues such as DST, e.g.

$e = strtotime('2011-03-31 12:30:00'); // 1301567400
$s = strtotime('2011-03-31 10:55:00'); // 1301561700
$d = $e - $s;                          //       5700
echo date(DateTime::RSS, $d);
// Thu, 01 Jan 1970 02:35:00 +0100
echo date('G:i:s', $d);
// 2:35:00

To circumvent this problem you could use

$d = new DateTime('@'.$d);
echo $d->format('G:i:s');

because DateTime does not take timezones into account when using it with timestamps.

EDIT

As the OP uses PHP 5.1.x there is another solution:

$end_time   = strtotime($_POST['t_date'].' '.$_POST['t_start'].' '.$_POST['s_ampm']);
$start_time = strtotime($_POST['t_date'].' '.$_POST['t_end'].' '.$_POST['e_ampm']);
$temp       = abs($end_time - $start_time);
echo gmdate('G:i:s', $temp);

But this only works if $start_time and $end_time are within a 24 hour timespan (as do all solutions presented except for the first one).

The manual solution (but it works in general and does not rely on any date-time-handling

$end_time   = strtotime($_POST['t_date'].' '.$_POST['t_start'].' '.$_POST['s_ampm']);
$start_time = strtotime($_POST['t_date'].' '.$_POST['t_end'].' '.$_POST['e_ampm']);
$temp       = abs($end_time - $start_time);

$hours   = floor($temp / 3600);
$minutes = floor( ($temp - $hours*3600) / 60 );
$seconds = $temp - $hours*3600 - $minutes*60;
$diff    = sprintf('%d:%02d:%02d', $hours, $minutes, $seconds);

This can easily be extended to days and weeks. Months and years will be difficult because they change their length throughout a year or throughout decades.


strtotime() takes the summer time in account. It depends on the current time zone. So your duration is the actual difference, taking hours in account, not the theoretical day difference. This feature is a nigmare in PHP for date calculation !

You can try with date_diff() if you have PHP >= 5.3.0


Your $end_time and $start_time variables are reversed.

Also date() takes into account for differences between the server time and GMT.

Just use

gmdate ('G:i:s', abs($temp))

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜