如何计算两个日期之间的小时差?
例如:
day1=2006-04-12 12:30:00
day2=2006-04-14 11:30:00
在这种情况下,结果应该是47小时。
较新版本的PHP提供了一些称为DateTime
,DateInterval
,DateTimeZone
和DatePeriod
的新类。这些类的好处在于,它们考虑了不同的时区、闰年、闰秒、夏令时等等。而且,使用它们非常容易。下面是如何使用这些对象来实现你想要的功能:
// Create two new DateTime-objects...
$date1 = new DateTime('2006-04-12T12:30:00');
$date2 = new DateTime('2006-04-14T11:30: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');
返回的DateInterval对象不仅提供了format
方法,还提供了其他方法。如果您只希望以小时为单位获取结果,可以像下面这样操作:
$date1 = new DateTime('2006-04-12T12:30:00');
$date2 = new DateTime('2006-04-14T11:30:00');
$diff = $date2->diff($date1);
$hours = $diff->h;
$hours = $hours + ($diff->days*24);
echo $hours;
以下是文档链接:
这些类还提供了一种面向过程/函数式的操作日期的方式。因此,请参阅概述: http://php.net/manual/book.datetime.php
$diff->d
等于0(因为我试图计算相隔两个月的日期之间的小时数):运行var_dump($diff)
显示了另一个参数:["days"]=>int(61)
,所以最终我使用了$hours = $diff->days * 24;
,结果接近于假设2个30天的月份总计有1440小时的“平均”时间,所以这比得到0的结果要好得多。(猜测我的PHP版本可能有点旧...) - semmelbroeselDateInterval::format()
的问题在于当我们想要特定单位的结果时。例如:24小时的差异将显示为 0
小时和 1
天。因此,如果天数不为空,我们需要注意并进行另一次计算。 - GusDeCooLDateDiff
不能给我们总小时数。感谢您的回答和指导,之前很困惑为什么我的差异少了一天的小时数,现在有所了解了! - Antony$t1 = strtotime( '2006-04-14 11:30:00' );
$t2 = strtotime( '2006-04-12 12:30:00' );
$diff = $t1 - $t2;
$hours = $diff / ( 60 * 60 );
$diff / 3600
? - Alex G为使用UTC或GMT时区提供另一种 DatePeriod
方法。
$start = new \DateTime('2006-04-12T12:30:00');
$end = new \DateTime('2006-04-14T11:30:00');
//determine what interval should be used - can change to weeks, months, etc
$interval = new \DateInterval('PT1H');
//create periods every hour between the two dates
$periods = new \DatePeriod($start, $interval, $end);
//count the number of objects within the periods
$hours = iterator_count($periods);
echo $hours . ' hours';
//difference between Unix Epoch
$diff = $end->getTimestamp() - $start->getTimestamp();
$hours = $diff / ( 60 * 60 );
echo $hours . ' hours (60 * 60)';
//difference between days
$diff = $end->diff($start);
$hours = $diff->h + ($diff->days * 24);
echo $hours . ' hours (days * 24)';
结果
47 hours (iterator_count)
47 hours (60 * 60)
47 hours (days * 24)
请注意,DatePeriod
在夏令时排除一小时,但在夏令时结束时不会添加另一个小时。因此,其使用取决于您所需的结果和日期范围。
请参阅当前的错误报告
//set timezone to UTC to disregard daylight savings
date_default_timezone_set('America/New_York');
$interval = new \DateInterval('PT1H');
//DST starts Apr. 2nd 02:00 and moves to 03:00
$start = new \DateTime('2006-04-01T12:00:00');
$end = new \DateTime('2006-04-02T12:00:00');
$periods = new \DatePeriod($start, $interval, $end);
$hours = iterator_count($periods);
echo $hours . ' hours';
//DST ends Oct. 29th 02:00 and moves to 01:00
$start = new \DateTime('2006-10-28T12:00:00');
$end = new \DateTime('2006-10-29T12:00:00');
$periods = new \DatePeriod($start, $interval, $end);
$hours = iterator_count($periods);
echo $hours . ' hours';
结果
#2006-04-01 12:00 EST to 2006-04-02 12:00 EDT
23 hours (iterator_count)
//23 hours (60 * 60)
//24 hours (days * 24)
#2006-10-28 12:00 EDT to 2006-10-29 12:00 EST
24 hours (iterator_count)
//25 hours (60 * 60)
//24 hours (days * 24)
#2006-01-01 12:00 EST to 2007-01-01 12:00 EST
8759 hours (iterator_count)
//8760 hours (60 * 60)
//8760 hours (days * 24)
//------
#2006-04-01 12:00 UTC to 2006-04-02 12:00 UTC
24 hours (iterator_count)
//24 hours (60 * 60)
//24 hours (days * 24)
#2006-10-28 12:00 UTC to 2006-10-29 12:00 UTC
24 hours (iterator_count)
//24 hours (60 * 60)
//24 hours (days * 24)
#2006-01-01 12:00 UTC to 2007-01-01 12:00 UTC
8760 hours (iterator_count)
//8760 hours (60 * 60)
//8760 hours (days * 24)
DateInterval
不接受 ISO 8601 规范中的小数值。因此,在 PHP 中 P1.2Y
不是一个有效的持续时间。 - Will B.iterator_count
无关,而是由于DatePeriod
无法在开始日期在结束日期之后的未来生成日期。请参见:https://3v4l.org/Ypsp1。要使用负日期,您需要指定一个负间隔,例如`DateInterval::createFromDateString('-1 hour');`,并且开始日期必须在过去或者结束日期之前。 - Will B.DatePeriod
的另一个微妙之处,因为默认情况下它将包括指定时间段之间的开始日期,除非它们小于或等于开始日期。实际上,您告诉 PHP 在两个日期之间创建一个持续1小时的时间段,在1秒钟内。您需要从日期对象中删除分钟和秒,因为它们在计算中不相关,使用 DateTime::setTime(date->format('H'), 0)
。https://3v4l.org/K7uss 这样,如果您超出了1秒的范围,就不会创建另一个日期。 - Will B.你的答案是:
round((strtotime($day2) - strtotime($day1))/(60*60))
获取两个日期(datetimes)之间的正确小时数,即使跨越夏令时更改,最简单的方法是使用Unix时间戳之差。Unix时间戳是自1970-01-01T00:00:00 UTC以来经过的秒数,忽略闰秒(这没问题,因为您可能不需要这种精度,并且因为考虑闰秒相当困难)。
将带有可选时区信息的日期时间字符串转换为Unix时间戳的最灵活方法是构造一个DateTime对象(可选地在构造函数中作为第二个参数使用DateTimeZone),然后调用其getTimestamp方法。
$str1 = '2006-04-12 12:30:00';
$str2 = '2006-04-14 11:30:00';
$tz1 = new DateTimeZone('Pacific/Apia');
$tz2 = $tz1;
$d1 = new DateTime($str1, $tz1); // tz is optional,
$d2 = new DateTime($str2, $tz2); // and ignored if str contains tz offset
$delta_h = ($d2->getTimestamp() - $d1->getTimestamp()) / 3600;
if ($rounded_result) {
$delta_h = round ($delta_h);
} else if ($truncated_result) {
$delta_h = intval($delta_h);
}
echo "Δh: $delta_h\n";
getTimestamp()
现在返回与format(“U”)
完全相同的值。前者是一个整数,而后者是一个字符串(效率稍低)。 - Walter TrossgetTimestamp()
。 - Arth//Calculate number of hours between pass and now
$dayinpass = "2013-06-23 05:09:12";
$today = time();
$dayinpass= strtotime($dayinpass);
echo round(abs($today-$dayinpass)/60/60);
<?
$day1 = "2014-01-26 11:30:00";
$day1 = strtotime($day1);
$day2 = "2014-01-26 12:30:00";
$day2 = strtotime($day2);
$diffHours = round(($day2 - $day1) / 3600);
echo $diffHours;
?>
很不幸,FaileN提供的解决方案并不能像Walter Tross所说的那样工作...因为一天可能不是24小时!
我喜欢尽可能使用PHP对象,为了更灵活性,我想出了以下函数:
/**
* @param DateTimeInterface $a
* @param DateTimeInterface $b
* @param bool $absolute Should the interval be forced to be positive?
* @param string $cap The greatest time unit to allow
*
* @return DateInterval The difference as a time only interval
*/
function time_diff(DateTimeInterface $a, DateTimeInterface $b, $absolute=false, $cap='H'){
// Get unix timestamps, note getTimeStamp() is limited
$b_raw = intval($b->format("U"));
$a_raw = intval($a->format("U"));
// Initial Interval properties
$h = 0;
$m = 0;
$invert = 0;
// Is interval negative?
if(!$absolute && $b_raw<$a_raw){
$invert = 1;
}
// Working diff, reduced as larger time units are calculated
$working = abs($b_raw-$a_raw);
// If capped at hours, calc and remove hours, cap at minutes
if($cap == 'H') {
$h = intval($working/3600);
$working -= $h * 3600;
$cap = 'M';
}
// If capped at minutes, calc and remove minutes
if($cap == 'M') {
$m = intval($working/60);
$working -= $m * 60;
}
// Seconds remain
$s = $working;
// Build interval and invert if necessary
$interval = new DateInterval('PT'.$h.'H'.$m.'M'.$s.'S');
$interval->invert=$invert;
return $interval;
}
像 date_diff()
这样的函数会创建一个 DateTimeInterval
对象,但最大的时间单位是小时,而不是年。可以像平常一样进行格式化。
$interval = time_diff($date_a, $date_b);
echo $interval->format('%r%H'); // For hours (with sign)
注意:我使用了format('U')
而不是getTimestamp()
,因为在手册中有相关的注释。另外请注意,64位系统才支持后纪元和负纪元日期!
Carbon 也是一个不错的选择。
来自他们的网站:
一个简单的 PHP API 扩展,用于 DateTime。http://carbon.nesbot.com/
示例:
use Carbon\Carbon;
//...
$day1 = Carbon::createFromFormat('Y-m-d H:i:s', '2006-04-12 12:30:00');
$day2 = Carbon::createFromFormat('Y-m-d H:i:s', '2006-04-14 11:30:00');
echo $day1->diffInHours($day2); // 47
//...
diff()
。它添加了很好的语法糖,如diffInHours
、diffInMintutes
、diffInSeconds
等等。$day1 = "2006-04-12 12:30:00"
$day1 = strtotime($day1);
$day2 = "2006-04-14 11:30:00"
$day2 = strtotime($day2);
$diffHours = round(($day2 - $day1) / 3600);
strftime()
将两个值都转换为时间戳,并通过3600分割差异,但这样总是有效吗?该死的夏令时! - Pekkastrtotime()
函数,只要使用默认时区或明确指定时区偏移量,它就会始终正常工作。没有理由诅咒夏令时。 - Walter Tross