如何使用PHP计算两个日期之间的差异?

我有两个日期的形式:

Start Date: 2007-03-24End Date: 2009-06-26

现在我需要通过以下形式找到这两者之间的区别:

2 years, 3 months and 2 days

如何在PHP中执行此操作?

1043848 次浏览

将其用于遗留代码(PHP<5.3)。有关最新解决方案,请参阅下面的Jurka的答案

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

编辑:显然,这样做的首选方式就像下面的Jurka所描述的。我的代码通常仅在您没有PHP 5.3或更高版本时才推荐。

评论中的一些人指出,上面的代码只是一个近似值。我仍然认为,对于大多数目的来说,这很好,因为范围的使用更多的是为了提供已经过去或剩余多少时间的感觉,而不是提供精度——如果你想这样做,只需输出日期。

尽管如此,我还是决定解决这些抱怨。如果你真的需要一个确切的范围,但还没有访问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)));

您可以使用

getdate()

函数返回一个包含提供的日期/时间的所有元素的数组:

$diff = abs($endDate - $startDate);$my_t=getdate($diff);print("$my_t[year] years, $my_t[month] months and $my_t[mday] days");

如果您的开始日期和结束日期是字符串格式,则使用

$startDate = strtotime($startDateStr);$endDate = strtotime($endDateStr);

在上述代码之前

我在以下页面找到了您的文章,其中包含许多用于php日期时间计算的参考。

使用PHP计算两个日期(和时间)之间的差异。以下页面提供了一系列不同的方法(总共7种),用于使用PHP执行日期/时间计算,以确定两个日期之间的时间差异(小时、月)、天、月或年。

PHP日期时间-7种方法来计算两个日期之间的差异

查看小时和分钟和秒…

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

我不知道你是否在使用PHP框架,但是很多PHP框架都有日期/时间库和助手来帮助你避免重新发明轮子。

例如CodeIgniter有timespan()函数。只需输入两个Unix时间戳,它将自动生成如下结果:

1 Year, 10 Months, 2 Weeks, 5 Days, 10 Hours, 16 Minutes

http://codeigniter.com/user_guide/helpers/date_helper.html

我建议使用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 ";

阅读更多PHP DateTime::diff手册

来自手册:

从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)
// If you just want to see the year difference then use this function.// Using the logic I've created you may also create month and day difference// which I did not provide here so you may have the efforts to use your brain.// :)$date1='2009-01-01';$date2='2010-01-01';echo getYearDifference ($date1,$date2);function getYearDifference($date1=strtotime($date1),$date2=strtotime($date2)){$year = 0;while($date2 > $date1 = strtotime('+1 year', $date1)){++$year;}return $year;}

我投票给尤尔卡回答,因为这是我最喜欢的,但我有一个pre-php.5.3版本…

我发现自己正在处理一个类似的问题——这也是我最初提出这个问题的原因——但只需要在时间上有所不同。但是我的函数也很好地解决了这个问题,而且我自己的库中没有任何地方可以将它保存在不会丢失和遗忘的地方,所以…希望这对某人有用。

/**** @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;}

和测试:

$oDate = new DateTime();$oDate->modify('+111402189 seconds');var_dump($oDate);var_dump(date_diff_array(new DateTime(), $oDate));

而结果:

object(DateTime)[2]public 'date' => string '2014-04-29 18:52:51' (length=19)public 'timezone_type' => int 3public '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

我从这里得到了最初的想法,我修改了它以供我使用(我希望我的修改也会显示在那个页面上)。

您可以通过从$aIntervals数组中删除它们来轻松删除您不想要的间隔(例如“周”),或者添加$aExclude参数,或者在输出字符串时将它们过滤掉。

当PHP 5.3(分别为date_diff())不可用时,我正在使用我编写的以下函数:

        function dateDifference($startDate, $endDate){$startDate = strtotime($startDate);$endDate = strtotime($endDate);if ($startDate === false || $startDate < 0 || $endDate === false || $endDate < 0 || $startDate > $endDate)return false;
$years = date('Y', $endDate) - date('Y', $startDate);
$endMonth = date('m', $endDate);$startMonth = date('m', $startDate);
// Calculate months$months = $endMonth - $startMonth;if ($months <= 0)  {$months += 12;$years--;}if ($years < 0)return false;
// Calculate the days$measure = ($months == 1) ? 'month' : 'months';$days = $endDate - strtotime('+' . $months . ' ' . $measure, $startDate);$days = date('z', $days);
return array($years, $months, $days);}
<?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);?>

看看下面的链接。这是迄今为止我找到的最好的答案…:)

function dateDiff ($d1, $d2) {
// Return the number of days between the two dates:return round(abs(strtotime($d1) - strtotime($d2))/86400);
} // end function dateDiff

无论哪个日期更早或更晚,当您传入日期参数。该函数使用PHP ABS()绝对值来总是返回一个正数作为两者之间的天数日期。

请记住,两个日期之间的天数不是包括两个日期。所以如果你在找天数由输入日期之间的所有日期(包括输入日期)表示,您需要将一(1)添加到此函数的结果中。

例如,差值(由上述函数返回)在2013-02-09和2013-02-14之间是5。但天数或由日期范围2013-02-09-2013-02-14表示的日期是6。

http://www.bizinfosys.com/php/date-difference.html

我有一些简单的逻辑:

<?phpper_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;?>

前段时间我写了一个format_date函数,因为这给出了关于你想要约会的多种选择

function format_date($date, $type, $seperator="-"){if($date){$day = date("j", strtotime($date));$month = date("n", strtotime($date));$year = date("Y", strtotime($date));$hour = date("H", strtotime($date));$min = date("i", strtotime($date));$sec = date("s", strtotime($date));
switch($type){case 0:  $date = date("Y".$seperator."m".$seperator."d",mktime($hour, $min, $sec, $month, $day, $year)); break;case 1:  $date = date("D, F j, Y",mktime($hour, $min, $sec, $month, $day, $year)); break;case 2:  $date = date("d".$seperator."m".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break;case 3:  $date = date("d".$seperator."M".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break;case 4:  $date = date("d".$seperator."M".$seperator."Y h:i A",mktime($hour, $min, $sec, $month, $day, $year)); break;case 5:  $date = date("m".$seperator."d".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break;case 6:  $date = date("M",mktime($hour, $min, $sec, $month, $day, $year)); break;case 7:  $date = date("Y",mktime($hour, $min, $sec, $month, $day, $year)); break;case 8:  $date = date("j",mktime($hour, $min, $sec, $month, $day, $year)); break;case 9:  $date = date("n",mktime($hour, $min, $sec, $month, $day, $year)); break;case 10:$diff = abs(strtotime($date) - strtotime(date("Y-m-d h:i:s")));$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));$date = $years . " years, " . $months . " months, " . $days . "days";}}return($date);}

DateInterval很好,但它有几个警告:

  1. 仅适用于PHP 5.3+(但这已经不是一个好借口了
  2. 仅支持年、月、日、小时、分钟和秒(无周)
  3. 它计算上述所有+天的差额(您不能仅在几个月内获得差额)

为了克服这个问题,我编写了以下代码(从@enobrev回答改进):

function date_dif($since, $until, $keys = 'year|month|week|day|hour|minute|second'){$date = array_map('strtotime', array($since, $until));
if ((count($date = array_filter($date, 'is_int')) == 2) && (sort($date) === true)){$result = array_fill_keys(explode('|', $keys), 0);
foreach (preg_grep('~^(?:year|month)~i', $result) as $key => $value){while ($date[1] >= strtotime(sprintf('+%u %s', $value + 1, $key), $date[0])){++$value;}
$date[0] = strtotime(sprintf('+%u %s', $result[$key] = $value, $key), $date[0]);}
foreach (preg_grep('~^(?:year|month)~i', $result, PREG_GREP_INVERT) as $key => $value){if (($value = intval(abs($date[0] - $date[1]) / strtotime(sprintf('%u %s', 1, $key), 0))) > 0){$date[0] = strtotime(sprintf('+%u %s', $result[$key] = $value, $key), $date[0]);}}
return $result;}
return false;}

它运行两个循环;第一个通过暴力强制处理相对间隔(年和月),第二个通过简单的算术计算额外的绝对间隔(所以它更快):

echo humanize(date_dif('2007-03-24', '2009-07-31', 'second')); // 74300400 secondsecho humanize(date_dif('2007-03-24', '2009-07-31', 'minute|second')); // 1238400 minutes, 0 secondsecho humanize(date_dif('2007-03-24', '2009-07-31', 'hour|minute|second')); // 20640 hours, 0 minutes, 0 secondsecho humanize(date_dif('2007-03-24', '2009-07-31', 'year|day')); // 2 years, 129 daysecho humanize(date_dif('2007-03-24', '2009-07-31', 'year|week')); // 2 years, 18 weeksecho humanize(date_dif('2007-03-24', '2009-07-31', 'year|week|day')); // 2 years, 18 weeks, 3 daysecho humanize(date_dif('2007-03-24', '2009-07-31')); // 2 years, 4 months, 1 week, 0 days, 0 hours, 0 minutes, 0 seconds
function humanize($array){$result = array();
foreach ($array as $key => $value){$result[$key] = $value . ' ' . $key;
if ($value != 1){$result[$key] .= 's';}}
return implode(', ', $result);}

最好的做法是使用PHP的#0(和#1)对象。每个日期都封装在一个DateTime对象中,然后可以在两者之间进行区分:

$first_date = new DateTime("2012-11-30 17:03:30");$second_date = new DateTime("2012-12-21 00:00:00");

DateTime对象将接受strtotime()的任何格式。如果需要更具体的日期格式,可以使用#2来创建DateTime对象。

在两个对象都被实例化之后,你用#0将一个对象从另一个对象中分离出来。

$difference = $first_date->diff($second_date);

$difference现在包含一个DateInterval对象,其中包含差异信息。Avar_dump()如下所示:

object(DateInterval)public 'y' => int 0public 'm' => int 0public 'd' => int 20public 'h' => int 6public 'i' => int 56public 's' => int 30public 'invert' => int 0public 'days' => int 20

要格式化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;}

现在剩下的就是在$differenceDateInterval对象上调用我们的函数:

echo format_interval($difference);

我们得到了正确的结果:

20天6小时56分30秒

用于实现目标的完整代码:

/*** 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);

一个简单的功能

function time_difference($time_1, $time_2, $limit = null){
$val_1 = new DateTime($time_1);$val_2 = new DateTime($time_2);
$interval = $val_1->diff($val_2);
$output = array("year" => $interval->y,"month" => $interval->m,"day" => $interval->d,"hour" => $interval->h,"minute" => $interval->i,"second" => $interval->s);
$return = "";foreach ($output AS $key => $value) {
if ($value == 1)$return .= $value . " " . $key . " ";elseif ($value >= 1)$return .= $value . " " . $key . "s ";
if ($key == $limit)return trim($return);}return trim($return);}

使用like

echo time_difference ($time_1, $time_2, "day");

会像2 years 8 months 2 days一样返回

您还可以使用以下代码按舍入分数返回日期差异$date1=$duedate;//分配到期日期echo$date2=date("Y-m-d"); // 当前日期$ts1=strtotime($date1);$ts2=strtotime($date2);$seconds_diff=$ts1-$ts2;echo$datadiff=ceil(($seconds_diff/3600)/24);//以天为单位返回

如果您使用php的地板方法而不是ceil,它将返回您的舍入分数。请在此处检查差异,有时如果您的登台服务器时区不同,那么实时站点时区在这种情况下,您可能会得到不同的结果,因此相应地更改条件。

一不做二不休:我刚刚回顾了几个解决方案,所有这些都提供了一个复杂的解决方案,使用的是ground(),然后舍入到一个26年12个月零2天的解决方案,应该是25年11个月零20天!!!

这是我对这个问题的看法:可能不是优雅的,可能没有很好的编码,但如果你不计算飞跃年,那么提供了一个更接近答案的答案,显然闰年可以编码成这个,但在这种情况下-正如其他人所说,也许你可以提供这个答案::我已经包括所有测试条件和print_r,以便您可以更清楚地看到结果的结构::在这里,

//设置输入日期/变量::

$ISOstartDate   = "1987-06-22";$ISOtodaysDate = "2013-06-22";

//我们需要将ISO yyyy-mm-dd格式分解为yyyy mm dd,如下所示::

$yDate[]=爆炸('-', $ISOstart Date);print_r($yDate);

$zDate[]=爆炸('-', $ISOtoday sDate);print_r($zDate);

// Lets Sort of the Years!// Lets Sort out the difference in YEARS between startDate and todaysDate ::$years = $zDate[0][0] - $yDate[0][0];
// We need to collaborate if the month = month = 0, is before or after the Years Anniversary ie 11 months 22 days or 0 months 10 days...if ($months == 0 and $zDate[0][1] > $ydate[0][1]) {$years = $years -1;}// TEST resultecho "\nCurrent years => ".$years;
// Lets Sort out the difference in MONTHS between startDate and todaysDate ::$months = $zDate[0][1] - $yDate[0][1];
// TEST resultecho "\nCurrent months => ".$months;
// Now how many DAYS has there been - this assumes that there is NO LEAP years, so the calculation is APPROXIMATE not 100%// Lets cross reference the startDates Month = how many days are there in each month IF m-m = 0 which is a years anniversary// We will use a switch to check the number of days between each month so we can calculate days before and after the years anniversary
switch ($yDate[0][1]){case 01:    $monthDays = '31';  break;  // Jancase 02:    $monthDays = '28';  break;  // Febcase 03:    $monthDays = '31';  break;  // Marcase 04:    $monthDays = '30';  break;  // Aprcase 05:    $monthDays = '31';  break;  // Maycase 06:    $monthDays = '30';  break;  // Juncase 07:    $monthDays = '31';  break;  // Julcase 08:    $monthDays = '31';  break;  // Augcase 09:    $monthDays = '30';  break;  // Septcase 10:    $monthDays = '31';  break;  // Octcase 11:    $monthDays = '30';  break;  // Novcase 12:    $monthDays = '31';  break;  // Dec};// TEST returnecho "\nDays in start month ".$yDate[0][1]." => ".$monthDays;

// Lets correct the problem with 0 Months - is it 11 months + days, or 0 months +days???
$days = $zDate[0][2] - $yDate[0][2] +$monthDays;echo "\nCurrent days => ".$days."\n";
// Lets now Correct the months to being either 11 or 0 Months, depending upon being + or - the years Anniversary date// At the same time build in error correction for Anniversary dates not being 1yr 0m 31d... see if ($days == $monthDays )if($days < $monthDays && $months == 0){$months = 11;       // If Before the years anniversary date}else    {$months = 0;        // If After the years anniversary date$years = $years+1;  // Add +1 to year$days = $days-$monthDays;   // Need to correct days to how many days after anniversary date};// Day correction for Anniversary datesif ($days == $monthDays )   // if todays date = the Anniversary DATE! set days to ZERO{$days = 0;          // days set toZERO so 1 years 0 months 0 days};
echo "\nTherefore, the number of years/ months/ days/ \nbetween start and todays date::\n\n";
printf("%d years, %d months, %d days\n", $years, $months, $days);

最终结果是::26年零个月零天

这就是我在2013年6月22日的业务时间-哎哟!

$date1 = date_create('2007-03-24');$date2 = date_create('2009-06-26');$interval = date_diff($date1, $date2);echo "difference : " . $interval->y . " years, " . $interval->m." months, ".$interval->d." days ";

这是我的函数。必需的PHP>=5.3.4。它使用DateTime类。非常快,快速,可以做两个日期之间的差异,甚至是所谓的“时间自”。

if(function_exists('grk_Datetime_Since') === FALSE){function grk_Datetime_Since($From, $To='', $Prefix='', $Suffix=' ago', $Words=array()){#   Est-ce qu'on calcul jusqu'à un moment précis ? Probablement pas, on utilise maintenantif(empty($To) === TRUE){$To = time();}
#   On va s'assurer que $From est numériqueif(is_int($From) === FALSE){$From = strtotime($From);};
#   On va s'assurer que $To est numériqueif(is_int($To) === FALSE){$To = strtotime($To);}
#   On a une erreur ?if($From === FALSE OR $From === -1 OR $To === FALSE OR $To === -1){return FALSE;}
#   On va créer deux objets de date$From = new DateTime(@date('Y-m-d H:i:s', $From), new DateTimeZone('GMT'));$To   = new DateTime(@date('Y-m-d H:i:s', $To), new DateTimeZone('GMT'));
#   On va calculer la différence entre $From et $Toif(($Diff = $From->diff($To)) === FALSE){return FALSE;}
#   On va merger le tableau des noms (par défaut, anglais)$Words = array_merge(array('year'      => 'year','years'     => 'years','month'     => 'month','months'    => 'months','week'      => 'week','weeks'     => 'weeks','day'       => 'day','days'      => 'days','hour'      => 'hour','hours'     => 'hours','minute'    => 'minute','minutes'   => 'minutes','second'    => 'second','seconds'   => 'seconds'), $Words);
#   On va créer la chaîne maintenantif($Diff->y > 1){$Text = $Diff->y.' '.$Words['years'];} elseif($Diff->y == 1){$Text = '1 '.$Words['year'];} elseif($Diff->m > 1){$Text = $Diff->m.' '.$Words['months'];} elseif($Diff->m == 1){$Text = '1 '.$Words['month'];} elseif($Diff->d > 7){$Text = ceil($Diff->d/7).' '.$Words['weeks'];} elseif($Diff->d == 7){$Text = '1 '.$Words['week'];} elseif($Diff->d > 1){$Text = $Diff->d.' '.$Words['days'];} elseif($Diff->d == 1){$Text = '1 '.$Words['day'];} elseif($Diff->h > 1){$Text = $Diff->h.' '.$Words['hours'];} elseif($Diff->h == 1){$Text = '1 '.$Words['hour'];} elseif($Diff->i > 1){$Text = $Diff->i.' '.$Words['minutes'];} elseif($Diff->i == 1){$Text = '1 '.$Words['minute'];} elseif($Diff->s > 1){$Text = $Diff->s.' '.$Words['seconds'];} else {$Text = '1 '.$Words['second'];}
return $Prefix.$Text.$Suffix;}}

使用示例:

echo time_diff_string('2013-05-01 00:22:35', 'now');echo time_diff_string('2013-05-01 00:22:35', 'now', true);

输出:

4 months ago4 months, 2 weeks, 3 days, 1 hour, 49 minutes, 15 seconds ago

功能:

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';}

这将尝试检测是否给出了时间戳,并且还将返回未来的日期/时间为负值:

<?php
function time_diff($start, $end = NULL, $convert_to_timestamp = FALSE) {// If $convert_to_timestamp is not explicitly set to TRUE,// check to see if it was accidental:if ($convert_to_timestamp || !is_numeric($start)) {// If $convert_to_timestamp is TRUE, convert to timestamp:$timestamp_start = strtotime($start);}else {// Otherwise, leave it as a timestamp:$timestamp_start = $start;}// Same as above, but make sure $end has actually been overridden with a non-null,// non-empty, non-numeric value:if (!is_null($end) && (!empty($end) && !is_numeric($end))) {$timestamp_end = strtotime($end);}else {// If $end is NULL or empty and non-numeric value, assume the end time desired// is the current time (useful for age, etc):$timestamp_end = time();}// Regardless, set the start and end times to an integer:$start_time = (int) $timestamp_start;$end_time = (int) $timestamp_end;
// Assign these values as the params for $then and $now:$start_time_var = 'start_time';$end_time_var = 'end_time';// Use this to determine if the output is positive (time passed) or negative (future):$pos_neg = 1;
// If the end time is at a later time than the start time, do the opposite:if ($end_time <= $start_time) {$start_time_var = 'end_time';$end_time_var = 'start_time';$pos_neg = -1;}
// Convert everything to the proper format, and do some math:$then = new DateTime(date('Y-m-d H:i:s', $$start_time_var));$now = new DateTime(date('Y-m-d H:i:s', $$end_time_var));
$years_then = $then->format('Y');$years_now = $now->format('Y');$years = $years_now - $years_then;
$months_then = $then->format('m');$months_now = $now->format('m');$months = $months_now - $months_then;
$days_then = $then->format('d');$days_now = $now->format('d');$days = $days_now - $days_then;
$hours_then = $then->format('H');$hours_now = $now->format('H');$hours = $hours_now - $hours_then;
$minutes_then = $then->format('i');$minutes_now = $now->format('i');$minutes = $minutes_now - $minutes_then;
$seconds_then = $then->format('s');$seconds_now = $now->format('s');$seconds = $seconds_now - $seconds_then;
if ($seconds < 0) {$minutes -= 1;$seconds += 60;}if ($minutes < 0) {$hours -= 1;$minutes += 60;}if ($hours < 0) {$days -= 1;$hours += 24;}$months_last = $months_now - 1;if ($months_now == 1) {$years_now -= 1;$months_last = 12;}
// "Thirty days hath September, April, June, and November" ;)if ($months_last == 9 || $months_last == 4 || $months_last == 6 || $months_last == 11) {$days_last_month = 30;}else if ($months_last == 2) {// Factor in leap years:if (($years_now % 4) == 0) {$days_last_month = 29;}else {$days_last_month = 28;}}else {$days_last_month = 31;}if ($days < 0) {$months -= 1;$days += $days_last_month;}if ($months < 0) {$years -= 1;$months += 12;}
// Finally, multiply each value by either 1 (in which case it will stay the same),// or by -1 (in which case it will become negative, for future dates).// Note: 0 * 1 == 0 * -1 == 0$out = new stdClass;$out->years = (int) $years * $pos_neg;$out->months = (int) $months * $pos_neg;$out->days = (int) $days * $pos_neg;$out->hours = (int) $hours * $pos_neg;$out->minutes = (int) $minutes * $pos_neg;$out->seconds = (int) $seconds * $pos_neg;return $out;}

示例用法:

<?php$birthday = 'June 2, 1971';$check_age_for_this_date = 'June 3, 1999 8:53pm';$age = time_diff($birthday, $check_age_for_this_date)->years;print $age;// 28

或:

<?php$christmas_2020 = 'December 25, 2020';$countdown = time_diff($christmas_2020);print_r($countdown);

我在PHP 5.2中遇到了同样的问题,并用MySQL解决了它。可能不是你想要的,但这会起作用并返回天数:

$datediff_q = $dbh->prepare("SELECT DATEDIFF(:date2, :date1)");$datediff_q->bindValue(':date1', '2007-03-24', PDO::PARAM_STR);$datediff_q->bindValue(':date2', '2009-06-26', PDO::PARAM_STR);$datediff = ($datediff_q->execute()) ? $datediff_q->fetchColumn(0) : false;

更多信息http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_datediff

由于每个人都在发布代码示例,这里是另一个版本。

我想要一个函数来显示从秒到年的差异(只有一个单位)。对于超过1天的周期,我希望它在午夜翻转(周一上午10点从周三上午9点看到是2天前,而不是1)。对于一个月以上的周期,我希望翻转在本月的同一天(包括30/31天的月份和闰年)。

这就是我想出的:

/*** Returns how long ago something happened in the past, showing it* as n seconds / minutes / hours / days / weeks / months / years ago.** For periods over a day, it rolls over at midnight (so doesn't depend* on current time of day), and it correctly accounts for month-lengths* and leap-years (months and years rollover on current day of month).** $param string $timestamp in DateTime format* $return string description of interval*/function ago($timestamp){$then = date_create($timestamp);
// for anything over 1 day, make it rollover on midnight$today = date_create('tomorrow'); // ie end of today$diff = date_diff($then, $today);
if ($diff->y > 0) return $diff->y.' year'.($diff->y>1?'s':'').' ago';if ($diff->m > 0) return $diff->m.' month'.($diff->m>1?'s':'').' ago';$diffW = floor($diff->d / 7);if ($diffW > 0) return $diffW.' week'.($diffW>1?'s':'').' ago';if ($diff->d > 1) return $diff->d.' day'.($diff->d>1?'s':'').' ago';
// for anything less than 1 day, base it off 'now'$now = date_create();$diff = date_diff($then, $now);
if ($diff->d > 0) return 'yesterday';if ($diff->h > 0) return $diff->h.' hour'.($diff->h>1?'s':'').' ago';if ($diff->i > 0) return $diff->i.' minute'.($diff->i>1?'s':'').' ago';return $diff->s.' second'.($diff->s==1?'':'s').' ago';}

“如果”日期存储在MySQL中,我发现在数据库级别进行差异计算更容易……然后根据日、小时、分钟、秒输出,酌情解析和显示结果……

mysql> select firstName, convert_tz(loginDate, '+00:00', '-04:00') as loginDate, TIMESTAMPDIFF(DAY, loginDate, now()) as 'Day', TIMESTAMPDIFF(HOUR, loginDate, now())+4 as 'Hour', TIMESTAMPDIFF(MINUTE, loginDate, now())+(60*4) as 'Min', TIMESTAMPDIFF(SECOND, loginDate, now())+(60*60*4) as 'Sec' from User_ where userId != '10158' AND userId != '10198' group by emailAddress order by loginDate desc;+-----------+---------------------+------+------+------+--------+| firstName | loginDate           | Day  | Hour | Min  | Sec    |+-----------+---------------------+------+------+------+--------+| Peter     | 2014-03-30 18:54:40 |    0 |    4 |  244 |  14644 || Keith     | 2014-03-30 18:54:11 |    0 |    4 |  244 |  14673 || Andres    | 2014-03-28 09:20:10 |    2 |   61 | 3698 | 221914 || Nadeem    | 2014-03-26 09:33:43 |    4 |  109 | 6565 | 393901 |+-----------+---------------------+------+------+------+--------+4 rows in set (0.00 sec)

非常简单:

    <?php$date1 = date_create("2007-03-24");echo "Start date: ".$date1->format("Y-m-d")."<br>";$date2 = date_create("2009-06-26");echo "End date: ".$date2->format("Y-m-d")."<br>";$diff = date_diff($date1,$date2);echo "Difference between start date and end date: ".$diff->format("%y years, %m months and %d days")."<br>";?>

有关详细信息,请查看以下链接:

PHP:date_diff-手动

请注意,它适用于PHP 5.3.0或更高版本。

您可以随时使用以下函数,该函数可以以年和月(即1年4个月)返回年龄

function getAge($dob, $age_at_date){$d1 = new DateTime($dob);$d2 = new DateTime($age_at_date);$age = $d2->diff($d1);$years = $age->y;$months = $age->m;
return $years.'.'.months;}

或者,如果您希望在当前日期计算年龄,则可以使用

function getAge($dob){$d1 = new DateTime($dob);$d2 = new DateTime(date());$age = $d2->diff($d1);$years = $age->y;$months = $age->m;
return $years.'.'.months;}

对于php版本>=5.3:创建两个日期对象,然后使用date_diff()函数。它将返回php日期间隔时间戳对象。看留档

$date1=date_create("2007-03-24");$date2=date_create("2009-06-26");$diff=date_diff($date1,$date2);echo $diff->format("%R%a days");
$date = '2012.11.13';$dateOfReturn = '2017.10.31';
$substract = str_replace('.', '-', $date);
$substract2 = str_replace('.', '-', $dateOfReturn);


$date1 = $substract;$date2 = $substract2;
$ts1 = strtotime($date1);$ts2 = strtotime($date2);
$year1 = date('Y', $ts1);$year2 = date('Y', $ts2);
$month1 = date('m', $ts1);$month2 = date('m', $ts2);
echo $diff = (($year2 - $year1) * 12) + ($month2 - $month1);

我更喜欢使用date_createdate_diff对象。

代码:

$date1 = date_create("2007-03-24");$date2 = date_create("2009-06-26");
$dateDifference = date_diff($date1, $date2)->format('%y years, %m months and %d days');
echo $dateDifference;

输出:

2 years, 3 months and 2 days

更多信息阅读PHP#0手册

根据手册date_diffe::diff()

这是可运行的代码

$date1 = date_create('2007-03-24');$date2 = date_create('2009-06-26');$diff1 = date_diff($date1,$date2);$daysdiff = $diff1->format("%R%a");$daysdiff = abs($daysdiff);

使用date_diff()尝试这个非常简单的答案,这是经过测试的。

$date1 = date_create("2017-11-27");$date2 = date_create("2018-12-29");$diff=date_diff($date1,$date2);$months = $diff->format("%m months");$years = $diff->format("%y years");$days = $diff->format("%d days");
echo $years .' '.$months.' '.$days;

输出是:

1 years 1 months 2 days

我想带来一个稍微不同的视角,这似乎没有被提及。

你可以用声明的方式解决这个问题(就像任何其他问题一样)。关键是问你需要的什么,而不是如何来到达那里。

在这里,你需要一个差异。但是那个差异是什么?这是一个间隔,正如在投票最多的答案中已经提到的那样。问题是如何得到它。不要显式调用diff()方法,你可以按开始日期和结束日期创建一个间隔,即按日期范围:

$startDate = '2007-03-24';$endDate = '2009-06-26';$range = new FromRange(new ISO8601DateTime($startDate), new ISO8601DateTime($endDate));

所有错综复杂的事情,比如闰年,都已经处理好了。现在,当你有一个固定开始日期时间的间隔时,你可以得到一个人类可读的版本:

var_dump((new HumanReadable($range))->value());

它准确地输出你需要的东西。

如果你需要一些自定义格式,这也不是问题。你可以使用ISO8601Formatted类,它接受带有六个参数的可调用对象:年、月、日、小时、分钟和秒:

(new ISO8601Formatted(new FromRange(new ISO8601DateTime('2017-07-03T14:27:39+00:00'),new ISO8601DateTime('2018-07-05T14:27:39.235487+00:00')),function (int $years, int $months, int $days, int $hours, int $minutes, int $seconds) {return $years >= 1 ? 'More than a year' : 'Less than a year';}))->value();

输出More than a year

有关此方法的更多信息,请查看快速入门

使用此功能

//function Diff between Dates////////////////////////////////////////////////////////////////////////PARA: Date Should In YYYY-MM-DD Format//RESULT FORMAT:// '%y Year %m Month %d Day %h Hours %i Minute %s Seconds' =>  1 Year 3 Month 14 Day 11 Hours 49 Minute 36 Seconds// '%y Year %m Month %d Day'                       =>  1 Year 3 Month 14 Days// '%m Month %d Day'                                     =>  3 Month 14 Day// '%d Day %h Hours'                                   =>  14 Day 11 Hours// '%d Day'                                                 =>  14 Days// '%h Hours %i Minute %s Seconds'         =>  11 Hours 49 Minute 36 Seconds// '%i Minute %s Seconds'                           =>  49 Minute 36 Seconds// '%h Hours                                          =>  11 Hours// '%a Days                                                =>  468 Days//////////////////////////////////////////////////////////////////////function dateDifference($date_1 , $date_2 , $differenceFormat = '%a' ){$datetime1 = date_create($date_1);$datetime2 = date_create($date_2);
$interval = date_diff($datetime1, $datetime2);
return $interval->format($differenceFormat);
}

仅根据需要设置参数$差异例如,我想用你的年龄来区分年份和月份和天数

日期差异(日期('Y-m-d')$date,'%y%m%d')

或其他格式

日期差异(日期('Y-m-d')$date,'%y-%m-%d')

function showTime($time){
$start      = strtotime($time);$end        = strtotime(date("Y-m-d H:i:s"));$minutes    = ($end - $start)/60;

// yearsif(($minutes / (60*24*365)) > 1){$years = floor($minutes/(60*24*365));return "From $years year( s ) ago";}

// monthesif(($minutes / (60*24*30)) > 1){$monthes = floor($minutes/(60*24*30));return "From $monthes monthe( s ) ago";}

// daysif(($minutes / (60*24)) > 1){$days = floor($minutes/(60*24));return "From $days day( s ) ago";}
// hoursif(($minutes / 60) > 1){$hours = floor($minutes/60);return "From $hours hour( s ) ago";}
// minutesif($minutes > 1){$minutes = floor($minutes);return "From $minutes minute( s ) ago";}}
echo showTime('2022-05-05 21:33:00');