如何计算两个日期之间的时差?
例如:
day1=2006-04-12 12:30:00
day2=2006-04-14 11:30:00
在这种情况下,结果应为47小时。
strtotime()
它,只要使用默认时区或显式指定时区偏移,它将始终有效。没有理由诅咒夏令时。
如何计算两个日期之间的时差?
例如:
day1=2006-04-12 12:30:00
day2=2006-04-14 11:30:00
在这种情况下,结果应为47小时。
strtotime()
它,只要使用默认时区或显式指定时区偏移,它将始终有效。没有理由诅咒夏令时。
Answers:
较新的PHP版本提供了一些新类叫DateTime
,DateInterval
,DateTimeZone
和DatePeriod
。此类的优点是,它考虑了不同的时区,leap年,leap秒,夏季等。此外,它非常易于使用。在此对象的帮助下,这是您想要的:
// 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
$date1 = new DateTime('2006-04-12T12:30:00 Europe/Berlin');
和$date2 = new DateTime('2006-04-14T11:30:00 America/New_York');
$diff->d
等于0的问题(因为我试图计算两个日期之间的时间,恰好相隔2个月):跑步var_dump($diff)
给我显示了另一个参数:["days"]=>int(61)
,所以我最终使用$hours = $diff->days * 24;
,它来了出接近给定的二三十天的月,所以这是寻找更好的比0的结果为1440个小时的“平均”(我猜的PHP版本是有点老了...)
$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
呢?
为DatePeriod
使用UTC或GMT时区提供另一种方法。
$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
DST排除一个小时,但DST结束时不增加一个小时。因此,其用法取决于您所需的结果和日期范围。
查看当前的错误报告
//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规范中的分数。因此P1.2Y
在PHP中不是有效的持续时间。
iterator_count
,这是由于DatePeriod
无法从开始日期到结束日期的将来生成日期。请参阅:3v4l.org/Ypsp1 以使用负数日期,您需要指定一个负数间隔,DateInterval::createFromDateString('-1 hour');
其起始日期为结束日期的过去。
DatePeriod
,因为默认情况下,它将包括指定时间段之间的开始日期,除非它们小于或等于开始日期。实际上,您是在告诉php在两个日期之间的1秒钟内创建1个小时的时间段。您需要使用来删除日期对象中的分钟和秒,因为它们与计算无关DateTime::setTime(date->format('H'), 0)
。3v4l.org/K7uss这样,如果您超出范围1秒钟,则不会创建另一个日期。
您的答案是:
round((strtotime($day2) - strtotime($day1))/(60*60))
即使在夏令时更改之间,也要获得两个日期(日期时间)之间正确的小时数,最简单的方法是使用Unix时间戳中的差异。Unix时间戳是从1970-01-01T00:00:00 UTC开始经过的秒数,忽略了,秒(这是可以的,因为您可能不需要这种精度,并且考虑到leap秒非常困难)。
将带有可选时区信息的datetime字符串转换为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")
。但是,前者是一个整数,而后者是一个字符串(此处效率较低)。
getTimestamp()
可以确定。
//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 = "2006-04-12 12:30:00"
$day1 = strtotime($day1);
$day2 = "2006-04-14 11:30:00"
$day2 = strtotime($day2);
$diffHours = round(($day2 - $day1) / 3600);
我猜strtotime()函数接受此日期格式。
不幸的是,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位!
此功能可以帮助您计算两个给定日期之间的精确年,月,$doj1
和$doj
。返回示例4.3表示4年3个月。
<?php
function cal_exp($doj1)
{
$doj1=strtotime($doj1);
$doj=date("m/d/Y",$doj1); //till date or any given date
$now=date("m/d/Y");
//$b=strtotime($b1);
//echo $c=$b1-$a2;
//echo date("Y-m-d H:i:s",$c);
$year=date("Y");
//$chk_leap=is_leapyear($year);
//$year_diff=365.25;
$x=explode("/",$doj);
$y1=explode("/",$now);
$yy=$x[2];
$mm=$x[0];
$dd=$x[1];
$yy1=$y1[2];
$mm1=$y1[0];
$dd1=$y1[1];
$mn=0;
$mn1=0;
$ye=0;
if($mm1>$mm)
{
$mn=$mm1-$mm;
if($dd1<$dd)
{
$mn=$mn-1;
}
$ye=$yy1-$yy;
}
else if($mm1<$mm)
{
$mn=12-$mm;
//$mn=$mn;
if($mm!=1)
{
$mn1=$mm1-1;
}
$mn+=$mn1;
if($dd1>$dd)
{
$mn+=1;
}
$yy=$yy+1;
$ye=$yy1-$yy;
}
else
{
$ye=$yy1-$yy;
$ye=$ye-1;
$mn=12-1;
if($dd1>$dd)
{
$ye+=1;
$mn=0;
}
}
$to=$ye." year and ".$mn." months";
return $ye.".".$mn;
/*return daysDiff($x[2],$x[0],$x[1]);
$days=dateDiff("/",$now,$doj)/$year_diff;
$days_exp=explode(".",$days);
return $years_exp=$days; //number of years exp*/
}
?>
<php
需要更改为<?php
或批准建议的编辑,以完全删除该错误。
这正在我的项目中工作。我认为,这将对您有所帮助。
如果日期在过去,则取反1。
如果日期在将来,则取反0。
$defaultDate = date('Y-m-d');
$datetime1 = new DateTime('2013-03-10');
$datetime2 = new DateTime($defaultDate);
$interval = $datetime1->diff($datetime2);
$days = $interval->format('%a');
$invert = $interval->invert;
要传递unix时间戳,请使用此符号
$now = time();
$now = new DateTime("@$now");
+0:00
使用时传递并输出@
。使用该DateTime::modify()
方法时,会将时间戳记作为+0:00
并输出当前时区。另一种使用方法是$date = new DateTime(); $date->setTimestamp($unix_timestamp);
:3v4l.org/BoAWI
碳也可能是一个不错的选择。
从他们的网站:
DateTime的简单PHP API扩展。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
//...
Carbon将DateTime类扩展为继承包括的方法diff()
。它增加了漂亮的糖,如diffInHours
,diffInMintutes
,diffInSeconds
等
首先,您应该根据日期范围创建一个时间间隔对象。仅通过此句中使用的措辞,就可以轻松确定所需的基本抽象。有一个时间间隔作为一个概念,还有多种实现它的方法,包括已经提到的一种方法-从一系列日期开始。因此,间隔看起来像这样:
$interval =
new FromRange(
new FromISO8601('2017-02-14T14:27:39+00:00'),
new FromISO8601('2017-03-14T14:27:39+00:00')
);
FromISO8601
具有相同的语义:这是创建的datetime对象from iso8601-formatted string
,因此是名称。
有间隔时,可以按自己的喜好设置格式。如果您需要几个小时的工作时间,则可以
(new TotalFullHours($interval))->value();
如果您想要最高的总小时数,请按以下步骤进行:
(new TotalCeiledHours($interval))->value();
有关此方法的更多信息和一些示例,请查看此条目。
除了@fyrye的非常有用的答案外,这是上述bug的不错解决方法(此 bug ),DatePeriod在进入夏季时减去一小时,而离开夏季时不减去一小时(因此,欧洲/柏林的三月有其正确的743小时,但十月为744,而不是745小时):
function getMonthHours(string $year, string $month, \DateTimeZone $timezone): int
{
// or whatever start and end \DateTimeInterface objects you like
$start = new \DateTimeImmutable($year . '-' . $month . '-01 00:00:00', $timezone);
$end = new \DateTimeImmutable((new \DateTimeImmutable($year . '-' . $month . '-01 23:59:59', $timezone))->format('Y-m-t H:i:s'), $timezone);
// count the hours just utilizing \DatePeriod, \DateInterval and iterator_count, hell yeah!
$hours = iterator_count(new \DatePeriod($start, new \DateInterval('PT1H'), $end));
// find transitions and check, if there is one that leads to a positive offset
// that isn't added by \DatePeriod
// this is the workaround for https://bugs.php.net/bug.php?id=75685
$transitions = $timezone->getTransitions((int)$start->format('U'), (int)$end->format('U'));
if (2 === count($transitions) && $transitions[0]['offset'] - $transitions[1]['offset'] > 0) {
$hours += (round(($transitions[0]['offset'] - $transitions[1]['offset'])/3600));
}
return $hours;
}
$myTimezoneWithDST = new \DateTimeZone('Europe/Berlin');
var_dump(getMonthHours('2020', '01', $myTimezoneWithDST)); // 744
var_dump(getMonthHours('2020', '03', $myTimezoneWithDST)); // 743
var_dump(getMonthHours('2020', '10', $myTimezoneWithDST)); // 745, finally!
$myTimezoneWithoutDST = new \DateTimeZone('UTC');
var_dump(getMonthHours('2020', '01', $myTimezoneWithoutDST)); // 744
var_dump(getMonthHours('2020', '03', $myTimezoneWithoutDST)); // 744
var_dump(getMonthHours('2020', '10', $myTimezoneWithoutDST)); // 744
PS:如果您检查(更长)的时间跨度(导致的过渡时间不止这两个),我的解决方法将不会涉及计算的小时数,以减少潜在的有趣副作用。在这种情况下,必须实施更复杂的解决方案。可以遍历所有找到的转换,并将当前转换与最后一个转换进行比较,并检查是否为DST true-> false。
strftime()
并将两个值都转换为时间戳,然后将差值除以3600,但这总是可行吗?该死,夏时制!