发现两次之间的差异。 (PHP / MySQL的)

时间:2011-03-31 13:57:46

标签: php mysql date 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:s', abs($temp));

所以我要说start_time的值是6:00:00而end_time 7:45:00我的持续时间是2:45:00:S

它总是比实际差异小一个小时。

我做错了什么?请赐教。

由于

4 个答案:

答案 0 :(得分:2)

问题

首先,请考虑一下:

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

UNIX时间戳是UNIX纪元后的300秒(或5分钟)。 date()会在您当前的当地时区显示此时间。

现在考虑一下:

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

这是UNIX纪元后的5个小时。但请记住,date()使用您当前的本地时区,因此,如果您在英国夏令时(GMT + 1)中,您会得到:

<?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"
?>

即使它不是1970年1月1日的BST,它现在是BST,这是用于日期显示的时区。

但你真的不想在1970年谈论约会...你只想格式化持续时间。持续时间是五个小时,但你要回来四个小时。

解决方案

您可以使用变体gmdate()来解决此问题,该变体始终使用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"
?>

通过使用PHP的面向对象的DateTime类,您还可以完全避免有限的UNIX时间戳:

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

在上下文中

现在考虑一下你自己的代码。在调用strtotime之后,$temp是一个UNIX时间戳,就像我在上面的示例中使用的日期一样。当您使用date()时,同样的问题也适用。

使用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);

使用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');

希望有所帮助。

答案 1 :(得分:1)

$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');

您不能在此处使用常规日期格式,因为它会将$temp视为UNIX时间戳,因此会受到时区和DST等问题的影响,例如

$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

要解决此问题,您可以使用

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

因为DateTime在使用时间戳时不会考虑时区。

修改

由于OP使用PHP 5.1.x,还有另一种解决方案:

$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);

但这仅在$start_time$end_time在24小时的时间范围内有效(除了第一个解决方案之外的所有解决方案)。

手动解决方案(但它一般有用,不依赖于任何日期时间处理

$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);

这可以很容易地延长到几天和几周。几个月和几年将是困难的,因为它们在一年或几十年内改变它们的长度。

答案 2 :(得分:1)

strtotime()将夏令时考虑在内。这取决于当前时区。 因此,您的持续时间是实际差异,需要花费数小时,而不是理论上的日差。 这个功能在PHP中用于日期计算是一个难题!

如果你有PHP&gt; = 5.3.0

,你可以试试date_diff()

答案 3 :(得分:1)

你的$ end_time和$ start_time变量是相反的。

此外,date()会考虑服务器时间与GMT之间的差异。

只需使用

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