php 如何使用PHP计算两个日期之间的差异?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/676824/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to calculate the difference between two dates using PHP?
提问by jurka
I have two dates of the form:
我有两个日期的形式:
Start Date: 2007-03-24
End Date: 2009-06-26
Now I need to find the difference between these two in the following form:
现在我需要以以下形式找到这两者之间的区别:
2 years, 3 months and 2 days
How can I do this in PHP?
我怎样才能在 PHP 中做到这一点?
采纳答案by Emil H
Use this for legacy code (PHP < 5.3). For up to date solution see jurka's answer below
将此用于遗留代码(PHP < 5.3)。有关最新解决方案,请参阅下面 jurka 的回答
You can use strtotime() to convert two dates to unix time and then calculate the number of seconds between them. From this it's rather easy to calculate different time periods.
您可以使用 strtotime() 将两个日期转换为 unix 时间,然后计算它们之间的秒数。由此可以很容易地计算出不同的时间段。
$date1 = "2007-03-24";
$date2 = "2009-06-26";
$diff = abs(strtotime($date2) - strtotime($date1));
$years = floor($diff / (365*60*60*24));
$months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24));
$days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24));
printf("%d years, %d months, %d days\n", $years, $months, $days);
Edit:Obviously the preferred way of doing this is like described by jurka below. My code is generally only recommended if you don't have PHP 5.3 or better.
编辑:显然,这样做的首选方式就像下面的 jurka 所描述的那样。如果您没有 PHP 5.3 或更高版本,通常只推荐使用我的代码。
Several people in the comments have pointed out that the code above is only an approximation. I still believe that for most purposes that's fine, since the usage of a range is more to provide a sense of how much time has passed or remains rather than to provide precision - if you want to do that, just output the date.
评论中有几个人指出,上面的代码只是一个近似值。我仍然相信,对于大多数目的来说,这很好,因为范围的使用更多地是为了提供已经过去或剩余多少时间的感觉,而不是提供精确度——如果你想这样做,只需输出日期。
Despite all that, I've decided to address the complaints. If you truly need an exact range but haven't got access to PHP 5.3, use the code below (it should work in PHP 4 as well). This is a direct port of the code that PHP uses internally to calculate ranges, with the exception that it doesn't take daylight savings time into account. That means that it's off by an hour at most, but except for that it should be correct.
尽管如此,我还是决定解决这些投诉。如果您确实需要一个确切的范围但无法访问 PHP 5.3,请使用下面的代码(它也应该适用于 PHP 4)。这是 PHP 内部用于计算范围的代码的直接移植,但它不考虑夏令时。这意味着它最多关闭一个小时,但除此之外它应该是正确的。
<?php
/**
* Calculate differences between two dates with precise semantics. Based on PHPs DateTime::diff()
* implementation by Derick Rethans. Ported to PHP by Emil H, 2011-05-02. No rights reserved.
*
* See here for original code:
* http://svn.php.net/viewvc/php/php-src/trunk/ext/date/lib/tm2unixtime.c?revision=302890&view=markup
* http://svn.php.net/viewvc/php/php-src/trunk/ext/date/lib/interval.c?revision=298973&view=markup
*/
function _date_range_limit($start, $end, $adj, $a, $b, $result)
{
if ($result[$a] < $start) {
$result[$b] -= intval(($start - $result[$a] - 1) / $adj) + 1;
$result[$a] += $adj * intval(($start - $result[$a] - 1) / $adj + 1);
}
if ($result[$a] >= $end) {
$result[$b] += intval($result[$a] / $adj);
$result[$a] -= $adj * intval($result[$a] / $adj);
}
return $result;
}
function _date_range_limit_days($base, $result)
{
$days_in_month_leap = array(31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
$days_in_month = array(31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
_date_range_limit(1, 13, 12, "m", "y", &$base);
$year = $base["y"];
$month = $base["m"];
if (!$result["invert"]) {
while ($result["d"] < 0) {
$month--;
if ($month < 1) {
$month += 12;
$year--;
}
$leapyear = $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0);
$days = $leapyear ? $days_in_month_leap[$month] : $days_in_month[$month];
$result["d"] += $days;
$result["m"]--;
}
} else {
while ($result["d"] < 0) {
$leapyear = $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0);
$days = $leapyear ? $days_in_month_leap[$month] : $days_in_month[$month];
$result["d"] += $days;
$result["m"]--;
$month++;
if ($month > 12) {
$month -= 12;
$year++;
}
}
}
return $result;
}
function _date_normalize($base, $result)
{
$result = _date_range_limit(0, 60, 60, "s", "i", $result);
$result = _date_range_limit(0, 60, 60, "i", "h", $result);
$result = _date_range_limit(0, 24, 24, "h", "d", $result);
$result = _date_range_limit(0, 12, 12, "m", "y", $result);
$result = _date_range_limit_days(&$base, &$result);
$result = _date_range_limit(0, 12, 12, "m", "y", $result);
return $result;
}
/**
* Accepts two unix timestamps.
*/
function _date_diff($one, $two)
{
$invert = false;
if ($one > $two) {
list($one, $two) = array($two, $one);
$invert = true;
}
$key = array("y", "m", "d", "h", "i", "s");
$a = array_combine($key, array_map("intval", explode(" ", date("Y m d H i s", $one))));
$b = array_combine($key, array_map("intval", explode(" ", date("Y m d H i s", $two))));
$result = array();
$result["y"] = $b["y"] - $a["y"];
$result["m"] = $b["m"] - $a["m"];
$result["d"] = $b["d"] - $a["d"];
$result["h"] = $b["h"] - $a["h"];
$result["i"] = $b["i"] - $a["i"];
$result["s"] = $b["s"] - $a["s"];
$result["invert"] = $invert ? 1 : 0;
$result["days"] = intval(abs(($one - $two)/86400));
if ($invert) {
_date_normalize(&$a, &$result);
} else {
_date_normalize(&$b, &$result);
}
return $result;
}
$date = "1986-11-10 19:37:22";
print_r(_date_diff(strtotime($date), time()));
print_r(_date_diff(time(), strtotime($date)));
回答by jurka
I suggest to use DateTime and DateInterval objects.
我建议使用 DateTime 和 DateInterval 对象。
$date1 = new DateTime("2007-03-24");
$date2 = new DateTime("2009-06-26");
$interval = $date1->diff($date2);
echo "difference " . $interval->y . " years, " . $interval->m." months, ".$interval->d." days ";
// shows the total amount of days (not divided into years, months and days like above)
echo "difference " . $interval->days . " days ";
read more php DateTime::diff manual
From the manual:
从手册:
As of PHP 5.2.2, DateTime objects can be compared using comparison operators.
从 PHP 5.2.2 开始,可以使用比较运算符来比较 DateTime 对象。
$date1 = new DateTime("now");
$date2 = new DateTime("tomorrow");
var_dump($date1 == $date2); // bool(false)
var_dump($date1 < $date2); // bool(true)
var_dump($date1 > $date2); // bool(false)
回答by Madara's Ghost
The best course of action is using PHP's DateTime(and DateInterval) objects. Each date is encapsulated in a DateTimeobject, and then a difference between the two can be made:
最好的做法是使用 PHP 的DateTime(和DateInterval)对象。每个日期都封装在一个DateTime对象中,然后可以对两者进行区分:
$first_date = new DateTime("2012-11-30 17:03:30");
$second_date = new DateTime("2012-12-21 00:00:00");
The DateTimeobject will accept any format strtotime()would. If an even more specific date format is needed, DateTime::createFromFormat()can be used to create the DateTimeobject.
该DateTime对象将接受任何格式strtotime()。如果需要更具体的日期格式,DateTime::createFromFormat()可用于创建DateTime对象。
After both objects were instantiated, you substract one from the other with DateTime::diff().
在两个对象都被实例化后,用 减去另一个对象DateTime::diff()。
$difference = $first_date->diff($second_date);
$differencenow holds a DateIntervalobject with the difference information. A var_dump()looks like this:
$difference现在持有一个DateInterval具有差异信息的对象。Avar_dump()看起来像这样:
object(DateInterval)
public 'y' => int 0
public 'm' => int 0
public 'd' => int 20
public 'h' => int 6
public 'i' => int 56
public 's' => int 30
public 'invert' => int 0
public 'days' => int 20
To format the DateIntervalobject, we'll need check each value and exclude it if it's 0:
要格式化DateInterval对象,我们需要检查每个值并在它为 0 时排除它:
/**
* Format an interval to show all existing components.
* If the interval doesn't have a time component (years, months, etc)
* That component won't be displayed.
*
* @param DateInterval $interval The interval
*
* @return string Formatted interval string.
*/
function format_interval(DateInterval $interval) {
$result = "";
if ($interval->y) { $result .= $interval->format("%y years "); }
if ($interval->m) { $result .= $interval->format("%m months "); }
if ($interval->d) { $result .= $interval->format("%d days "); }
if ($interval->h) { $result .= $interval->format("%h hours "); }
if ($interval->i) { $result .= $interval->format("%i minutes "); }
if ($interval->s) { $result .= $interval->format("%s seconds "); }
return $result;
}
All that's left now is to call our function on the $differenceDateIntervalobject:
现在剩下的就是在$differenceDateInterval对象上调用我们的函数:
echo format_interval($difference);
And we get the correct result:
我们得到了正确的结果:
20 days 6 hours 56 minutes 30 seconds
20 天 6 小时 56 分 30 秒
The complete code used to achieve the goal:
用于实现目标的完整代码:
/**
* Format an interval to show all existing components.
* If the interval doesn't have a time component (years, months, etc)
* That component won't be displayed.
*
* @param DateInterval $interval The interval
*
* @return string Formatted interval string.
*/
function format_interval(DateInterval $interval) {
$result = "";
if ($interval->y) { $result .= $interval->format("%y years "); }
if ($interval->m) { $result .= $interval->format("%m months "); }
if ($interval->d) { $result .= $interval->format("%d days "); }
if ($interval->h) { $result .= $interval->format("%h hours "); }
if ($interval->i) { $result .= $interval->format("%i minutes "); }
if ($interval->s) { $result .= $interval->format("%s seconds "); }
return $result;
}
$first_date = new DateTime("2012-11-30 17:03:30");
$second_date = new DateTime("2012-12-21 00:00:00");
$difference = $first_date->diff($second_date);
echo format_interval($difference);
回答by khaldonno
View Hours and Minuts and Seconds..
查看小时和分钟和秒..
$date1 = "2008-11-01 22:45:00";
$date2 = "2009-12-04 13:44:01";
$diff = abs(strtotime($date2) - strtotime($date1));
$years = floor($diff / (365*60*60*24));
$months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24));
$days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24));
$hours = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24)/ (60*60));
$minuts = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24 - $hours*60*60)/ 60);
$seconds = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24 - $hours*60*60 - $minuts*60));
printf("%d years, %d months, %d days, %d hours, %d minuts\n, %d seconds\n", $years, $months, $days, $hours, $minuts, $seconds);
回答by casper123
Take a look at the following link. This is the best answer I've found so far.. :)
看看下面的链接。这是迄今为止我找到的最好的答案.. :)
function dateDiff ($d1, $d2) {
// Return the number of days between the two dates:
return round(abs(strtotime($d1) - strtotime($d2))/86400);
} // end function dateDiff
It doesn't matter which date is earlier or later when you pass in the date parameters. The function uses the PHP ABS() absolute value to always return a postive number as the number of days between the two dates.
Keep in mind that the number of days between the two dates is NOT inclusive of both dates. So if you are looking for the number of days represented by all the dates between and including the dates entered, you will need to add one (1) to the result of this function.
For example, the difference (as returned by the above function) between 2013-02-09 and 2013-02-14 is 5. But the number of days or dates represented by the date range 2013-02-09 - 2013-02-14 is 6.
传入日期参数时,哪个日期更早或更晚都没有关系。该函数使用 PHP ABS() 绝对值始终返回一个正数作为两个日期之间的天数。
请记住,两个日期之间的天数不包括两个日期。因此,如果您要查找输入日期之间(包括输入日期)的所有日期所代表的天数,则需要将此函数的结果加一 (1)。
例如,2013-02-09 和 2013-02-14 之间的差异(由上述函数返回)是 5。但是日期范围 2013-02-09 - 2013-02- 表示的天数或日期数14 是 6。
回答by enobrev
I voted for jurka's answeras that's my favorite, but I have a pre-php.5.3 version...
我投票支持jurka的答案,因为这是我最喜欢的,但我有一个 pre-php.5.3 版本......
I found myself working on a similar problem - which is how I got to this question in the first place - but just needed a difference in hours. But my function solved this one pretty nicely as well and I don't have anywhere in my own library to keep it where it won't get lost and forgotten, so... hope this is useful to someone.
我发现自己正在解决一个类似的问题——这就是我最初如何解决这个问题的——但只需要几个小时的不同。但是我的函数也很好地解决了这个问题,我自己的库中没有任何地方可以将它保存在不会丢失和遗忘的地方,所以......希望这对某人有用。
/**
*
* @param DateTime $oDate1
* @param DateTime $oDate2
* @return array
*/
function date_diff_array(DateTime $oDate1, DateTime $oDate2) {
$aIntervals = array(
'year' => 0,
'month' => 0,
'week' => 0,
'day' => 0,
'hour' => 0,
'minute' => 0,
'second' => 0,
);
foreach($aIntervals as $sInterval => &$iInterval) {
while($oDate1 <= $oDate2){
$oDate1->modify('+1 ' . $sInterval);
if ($oDate1 > $oDate2) {
$oDate1->modify('-1 ' . $sInterval);
break;
} else {
$iInterval++;
}
}
}
return $aIntervals;
}
And the test:
和测试:
$oDate = new DateTime();
$oDate->modify('+111402189 seconds');
var_dump($oDate);
var_dump(date_diff_array(new DateTime(), $oDate));
And the result:
结果:
object(DateTime)[2]
public 'date' => string '2014-04-29 18:52:51' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'America/New_York' (length=16)
array
'year' => int 3
'month' => int 6
'week' => int 1
'day' => int 4
'hour' => int 9
'minute' => int 3
'second' => int 8
I got the original idea from here, which I modified for my uses (and I hope my modification will show on that page as well).
我从这里得到了最初的想法,我对其进行了修改(我希望我的修改也能显示在该页面上)。
You can very easily remove intervals you don't want (say "week") by removing them from the $aIntervalsarray, or maybe adding an $aExcludeparameter, or just filter them out when you output the string.
通过从$aIntervals数组中删除它们,或者添加一个$aExclude参数,或者在输出字符串时将它们过滤掉,您可以非常轻松地删除您不想要的间隔(比如“周”)。
回答by vengat
<?php
$today = strtotime("2011-02-03 00:00:00");
$myBirthDate = strtotime("1964-10-30 00:00:00");
printf("Days since my birthday: ", ($today - $myBirthDate)/60/60/24);
?>
回答by Jake Wilson
I don't know if you are using a PHP framework or not, but a lot of PHP frameworks have date/time libraries and helpers to help keep you from reinventing the wheel.
我不知道您是否在使用 PHP 框架,但是很多 PHP 框架都有日期/时间库和帮助程序来帮助您避免重新发明轮子。
For example CodeIgniter has the timespan()function. Simply input two Unix timestamps and it will automatically generate a result like this:
比如 CodeIgniter 就有这个timespan()功能。只需输入两个 Unix 时间戳,它就会自动生成如下结果:
1 Year, 10 Months, 2 Weeks, 5 Days, 10 Hours, 16 Minutes
回答by Glavi?
Use example :
使用示例:
echo time_diff_string('2013-05-01 00:22:35', 'now');
echo time_diff_string('2013-05-01 00:22:35', 'now', true);
Output :
输出 :
4 months ago
4 months, 2 weeks, 3 days, 1 hour, 49 minutes, 15 seconds ago
Function :
功能 :
function time_diff_string($from, $to, $full = false) {
$from = new DateTime($from);
$to = new DateTime($to);
$diff = $to->diff($from);
$diff->w = floor($diff->d / 7);
$diff->d -= $diff->w * 7;
$string = array(
'y' => 'year',
'm' => 'month',
'w' => 'week',
'd' => 'day',
'h' => 'hour',
'i' => 'minute',
's' => 'second',
);
foreach ($string as $k => &$v) {
if ($diff->$k) {
$v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
} else {
unset($string[$k]);
}
}
if (!$full) $string = array_slice($string, 0, 1);
return $string ? implode(', ', $string) . ' ago' : 'just now';
}
回答by Hardik Raval
I have some simple logic for that:
我有一些简单的逻辑:
<?php
per_days_diff('2011-12-12','2011-12-29')
function per_days_diff($start_date, $end_date) {
$per_days = 0;
$noOfWeek = 0;
$noOfWeekEnd = 0;
$highSeason=array("7", "8");
$current_date = strtotime($start_date);
$current_date += (24 * 3600);
$end_date = strtotime($end_date);
$seassion = (in_array(date('m', $current_date), $highSeason))?"2":"1";
$noOfdays = array('');
while ($current_date <= $end_date) {
if ($current_date <= $end_date) {
$date = date('N', $current_date);
array_push($noOfdays,$date);
$current_date = strtotime('+1 day', $current_date);
}
}
$finalDays = array_shift($noOfdays);
//print_r($noOfdays);
$weekFirst = array("week"=>array(),"weekEnd"=>array());
for($i = 0; $i < count($noOfdays); $i++)
{
if ($noOfdays[$i] == 1)
{
//echo "This is week";
//echo "<br/>";
if($noOfdays[$i+6]==7)
{
$noOfWeek++;
$i=$i+6;
}
else
{
$per_days++;
}
//array_push($weekFirst["week"],$day);
}
else if($noOfdays[$i]==5)
{
//echo "This is weekend";
//echo "<br/>";
if($noOfdays[$i+2] ==7)
{
$noOfWeekEnd++;
$i = $i+2;
}
else
{
$per_days++;
}
//echo "After weekend value:- ".$i;
//echo "<br/>";
}
else
{
$per_days++;
}
}
/*echo $noOfWeek;
echo "<br/>";
echo $noOfWeekEnd;
echo "<br/>";
print_r($per_days);
echo "<br/>";
print_r($weekFirst);
*/
$duration = array("weeks"=>$noOfWeek, "weekends"=>$noOfWeekEnd, "perDay"=>$per_days, "seassion"=>$seassion);
return $duration;
?>

