请注意,大多数数学计算示例的硬性限制为 2038-01-18 日期,不适用于虚构日期。
由于缺少基于 DateTime 和 DateInterval 的示例,我想提供一个多功能函数来满足 OP 的需求和其他想要复合经过时间段的人,例如 1 month 2 days ago。连同一堆其他用例,例如显示日期而不是经过时间的限制,或者过滤掉经过时间结果的部分。
此外,大多数示例都假设过去时间是从当前时间开始的,下面的函数允许用所需的结束日期覆盖它。
/**
* multi-purpose function to calculate the time elapsed between $start and optional $end
* @param string|null $start the date string to start calculation
* @param string|null $end the date string to end calculation
* @param string $suffix the suffix string to include in the calculated string
* @param string $format the format of the resulting date if limit is reached or no periods were found
* @param string $separator the separator between periods to use when filter is not true
* @param null|string $limit date string to stop calculations on and display the date if reached - ex: 1 month
* @param bool|array $filter false to display all periods, true to display first period matching the minimum, or array of periods to display ['year', 'month']
* @param int $minimum the minimum value needed to include a period
* @return string
*/
function elapsedTimeString($start, $end = null, $limit = null, $filter = true, $suffix = 'ago', $format = 'Y-m-d', $separator = ' ', $minimum = 1)
{
$dates = (object) array(
'start' => new DateTime($start ? : 'now'),
'end' => new DateTime($end ? : 'now'),
'intervals' => array('y' => 'year', 'm' => 'month', 'd' => 'day', 'h' => 'hour', 'i' => 'minute', 's' => 'second'),
'periods' => array()
);
$elapsed = (object) array(
'interval' => $dates->start->diff($dates->end),
'unknown' => 'unknown'
);
if ($elapsed->interval->invert === 1) {
return trim('0 seconds ' . $suffix);
}
if (false === empty($limit)) {
$dates->limit = new DateTime($limit);
if (date_create()->add($elapsed->interval) > $dates->limit) {
return $dates->start->format($format) ? : $elapsed->unknown;
}
}
if (true === is_array($filter)) {
$dates->intervals = array_intersect($dates->intervals, $filter);
$filter = false;
}
foreach ($dates->intervals as $period => $name) {
$value = $elapsed->interval->$period;
if ($value >= $minimum) {
$dates->periods[] = vsprintf('%1$s %2$s%3$s', array($value, $name, ($value !== 1 ? 's' : '')));
if (true === $filter) {
break;
}
}
}
if (false === empty($dates->periods)) {
return trim(vsprintf('%1$s %2$s', array(implode($separator, $dates->periods), $suffix)));
}
return $dates->start->format($format) ? : $elapsed->unknown;
}
需要注意的一点 - 所提供过滤器值的检索间隔不会延续到下一个周期。过滤器仅显示提供的周期的结果值,并且不会重新计算周期以仅显示所需的过滤器总数。
用法
由于 OP 需要显示最高时段(截至 2015-02-24)。
echo elapsedTimeString('2010-04-26');
/** 4 years ago */
显示复合期间并提供自定义结束日期(请注意缺少提供的时间和虚构的日期)。
echo elapsedTimeString('1920-01-01', '2500-02-24', null, false);
/** 580 years 1 month 23 days ago */
显示过滤周期的结果(数组的顺序无关紧要).
echo elapsedTimeString('2010-05-26', '2012-02-24', null, ['month', 'year']);
/** 1 year 8 months ago */
如果达到限制,则以提供的格式(默认 Y-m-d)显示开始日期。
echo elapsedTimeString('2010-05-26', '2012-02-24', '1 year');
/** 2010-05-26 */
还有很多其他用例。它也可以很容易地适应接受 unix 时间戳和/或 DateInterval 对象作为开始、结束或限制参数。