我有两个日期:
Start Date: 2007-03-24 End Date: 2009-06-26
现在我需要通过以下形式找到这两者之间的差异:
2 years, 3 months and 2 days
我怎么能用PHP做到这一点?
我建议使用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)
对于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在内部用于计算范围的代码的直接端口,但不考虑夏令时.这意味着它最多只有一个小时,但除此之外它应该是正确的.
= $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)));
最好的做法是使用PHP的DateTime
(和DateInterval
)对象.每个日期都封装在一个DateTime
对象中,然后两者之间的差异可以做出:
$first_date = new DateTime("2012-11-30 17:03:30"); $second_date = new DateTime("2012-12-21 00:00:00");
该DateTime
对象将接受任何格式strtotime()
.如果需要更具体的日期格式,DateTime::createFromFormat()
可以使用它来创建DateTime
对象.
在实例化两个对象之后,用另一个对象减去一个DateTime::diff()
.
$difference = $first_date->diff($second_date);
$difference
现在持有一个DateInterval
具有差异信息的对象.A var_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
要格式化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; }
现在剩下的就是在$difference
DateInterval
对象上调用我们的函数:
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);
查看时间和分钟和秒...
$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);
看看以下链接.这是我到目前为止找到的最佳答案.. :)
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
我投票支持jurka的答案,因为这是我最喜欢的,但我有一个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 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
我从这里得到了最初的想法,我为我的用途进行了修改(我希望我的修改也将在该页面上显示).
您可以通过从$aIntervals
阵列中删除它们,或者可能添加$aExclude
参数,或者只是在输出字符串时将其过滤掉,从而非常轻松地删除不需要的间隔(例如"周").
我不知道你是否使用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
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 ago 4 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'; }
我有一些简单的逻辑:
array(),"weekEnd"=>array()); for($i = 0; $i < count($noOfdays); $i++) { if ($noOfdays[$i] == 1) { //echo "This is week"; //echo "
"; 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 "
"; if($noOfdays[$i+2] ==7) { $noOfWeekEnd++; $i = $i+2; } else { $per_days++; } //echo "After weekend value:- ".$i; //echo "
"; } else { $per_days++; } } /*echo $noOfWeek; echo "
"; echo $noOfWeekEnd; echo "
"; print_r($per_days); echo "
"; print_r($weekFirst); */ $duration = array("weeks"=>$noOfWeek, "weekends"=>$noOfWeekEnd, "perDay"=>$per_days, "seassion"=>$seassion); return $duration; ?>
你可以使用
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);
在上面的代码之前
// 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; }
这是我的功能.必需的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 maintenant if(empty($To) === TRUE){ $To = time(); } # On va s'assurer que $From est numérique if(is_int($From) === FALSE){ $From = strtotime($From); }; # On va s'assurer que $To est numérique if(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 $To if(($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 maintenant if($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; } }
我更喜欢使用date_create
和date_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 date_diff
手册
根据manual
date_diff
是DateTime :: diff()的别名
我在下一页上找到了您的文章,其中包含许多PHP日期时间计算的参考.
使用PHP计算两个日期(和时间)之间的差异.以下页面提供了一系列不同的方法(总共7个),用于使用PHP执行日期/时间计算,以确定两个日期之间的时间差(小时数,小时数,天数,月数或年数).
请参阅PHP日期时间 - 计算2个日期之间差异的7种方法.
这将尝试检测是否给出了时间戳,并且还将未来的日期/时间作为负值返回:
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; }
用法示例:
years; print $age;// 28
要么:
17> ElasticThoug..:"如果"日期存储在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)