计算 PHP 中日期之间的绝对差异
Calculate Absolute Differences between Dates in PHP
我正在尝试创建一个函数来找出两个日期时间之间的差异,但我希望能够 return 每个日期时间的绝对值。
说相差15分20秒,我希望能够输出15分,20秒,或者920秒。这也将扩展为数天、数月、数年。所以 2 天 12 分钟可能是 2 天、48 小时、2892 分钟或 173520 秒。
我最初是从我自己的代码开始的,但想在考虑天、月和年时考虑适当的差异,所以我改为使用 DateDiff,但我现在发现它不能按我想要的方式工作。
到目前为止,这是我的代码
define( 'MINUTE_IN_SECONDS', 60 );
define( 'HOUR_IN_SECONDS', 60 * MINUTE_IN_SECONDS );
define( 'DAY_IN_SECONDS', 24 * HOUR_IN_SECONDS );
define( 'WEEK_IN_SECONDS', 7 * DAY_IN_SECONDS );
define( 'MONTH_IN_SECONDS', 30 * DAY_IN_SECONDS );
define( 'YEAR_IN_SECONDS', 365 * DAY_IN_SECONDS );
/**
* Output a length between times in friendly format
*
* @param string $date1 Date/Time from in Y-m-d H:i:s format.
* @param string $date2 Date/Time to in Y-m-d H:i:s format.
* @param string $length Length of output. Set to "l" for detailed down to the second. Defaults to short if nothing entered.
* @param string $format Format to return the output in. Based on {@link https://www.php.net/manual/en/dateinterval.format.php PHP Date Interval Format}.
* If no format is set, the function will try assume the best output
*
* @return string Will return the requested output.
*/
function friendlyDtmDiff($date1, $date2, $length = '', $format = '') {
// Create DateTime for diff()
$dt1 = new \DateTime($date1);
$dt2 = new \DateTime($date2);
// Check if $dt2 ($date2) is before $dt1 ($date1) and
// swap the values if they are, also outputing a negative sign
if($dt2 < $dt1) {
$dtHolder = $dt1->format('Y-m-d H:i:s');
$dt1 = new \DateTime($dt2->format('Y-m-d H:i:s'));
$dt2 = new \DateTime($dtHolder);
$r = '-';
} else {
$r = '';
}
// Set the interval
$interval = $dt1->diff($dt2);
// Assume best output options
if(empty($format) || $format == '') {
// Difference in seconds
$diffSecs = $dt2->getTimestamp() - $dt1->getTimestamp();
if($diffSecs > YEAR_IN_SECONDS) { // Assume Years
$format = 'y';
} else if($diffSecs > MONTH_IN_SECONDS) { // Assume Months
$format = 'm';
} else if($diffSecs > DAY_IN_SECONDS) { // Assume Days
$format = 'd';
} else if($diffSecs > HOUR_IN_SECONDS) { // Assume Hours
$format = 'h';
} else if($diffSecs > MINUTE_IN_SECONDS) { // Assume Minutes
$format = 'i';
} else {// Assume seconds
$format = 's';
}
}
switch ($format) {
// Return seconds
case 's':
return $interval->format('%s seconds');
break;
// Return seconds padded
case 'S':
return $interval->format('%S seconds');
break;
// Return minutes
case 'i':
return ($length == 'l') ? $r . $interval->format('%i minutes and %s seconds') : $r . $interval->format('%i minutes') ;
break;
// Return minutes padded
case 'I':
return ($length == 'l') ? $r . $interval->format('%I minutes and %S seconds') : $r . $interval->format('%I minutes') ;
break;
// Return hours
case 'h':
return ($length == 'l') ? $r . $interval->format('%h hours, %i minutes, and %s seconds') : $r . $interval->format('%h hours') ;
break;
// Return hours padded
case 'H':
return ($length == 'l') ? $r . $interval->format('%H hours, %I minutes, and %S seconds') : $r . $interval->format('%H hours') ;
break;
// Return days
case 'a':
case 'd':
return ($length == 'l') ? $r . $interval->format('%d days, %h hours, %i minutes, and %s seconds') : $r . $interval->format('%d days') ;
break;
// Return days padded
case 'D':
return ($length == 'l') ? $r . $interval->format('%D days, %H hours, %I minutes, and %S seconds') : $r . $interval->format('%D days') ;
break;
// Return months
case 'm':
return ($length == 'l') ? $r . $interval->format('%m months, %d days, %h hours, %i minutes, and %s seconds') : $r . $interval->format('%m months') ;
break;
// Return months padded
case 'M':
return ($length == 'l') ? $r . $interval->format('%M months, %D days, %H hours, %I minutes, and %S seconds') : $r . $interval->format('%M months') ;
break;
default:
return 'not available';
break;
}
}
这是代码示例
$dtmNow = new \DateTime();
$authExpireDtm = new \DateTime();
$authExpireDtm->modify('+15 minutes');
echo friendlyDtmDiff($dtmNow->format('Y-m-d H:i:s'), $authExpireDtm->format('Y-m-d H:i:s'), 'l', 's');
我想输出900 seconds
,但它输出0 seconds
,这是$interval
有
的对象
DateInterval Object ( [y] => 0 [m] => 0 [d] => 0 [h] => 0 [i] => 15 [s] => 0 [f] => 0 [weekday] => 0 [weekday_behavior] => 0 [first_last_day_of] => 0 [invert] => 0 [days] => 0 [special_type] => 0 [special_amount] => 0 [have_weekday_relative] => 0 [have_special_relative] => 0 )
如您所见,s
项下没有任何内容(0
),所以我的功能当然是returning 0 seconds
。我想知道如何让它达到 return 900
秒。我知道比较时间(小时、分钟、秒)很容易,但我想在转换日、月、年时准确。
因此,如果我输入 2020-02-28 00:00:00
和 2020-03-01 00:00:00
,它将 return 172800 seconds
或 2880 minutes
,但如果我输入 2019-02-28 00:00:00
2019-03-01 00:00:00
它将 return 86400 seconds
或 1440 minutes
有谁能为我指明正确的方向以实现我想要的结果
这是一个可以完成您想要的 99% 的函数(它不会在 length != 'l'
时实现舍入,也不会从 1 years
中删除 s
).不输出 0 个值,尽管您可以添加一个参数来控制它。
function friendlyDtmDiff($date1, $date2, $length = '', $format = '') {
// Create DateTime for diff()
$dt1 = new \DateTime($date1);
$dt2 = new \DateTime($date2);
// Create intervals
if ($dt1 < $dt2) {
$sign = '';
$interval = $dt1->diff($dt2);
}
else {
$sign = '-';
$interval = $dt2->diff($dt1);
}
// Output format (minimum 2 digits for upper case formats)
$of = ($format < 'a') ? '%02d' : '%d';
// generate output using an array of terms to be imploded
$output = array();
// create time components
switch ($format) {
case 'Y':
case 'y':
$years = $interval->y;
if ($years) $output[] = sprintf("$of years", $years);
if ($length != 'l') break;
$interval->y = 0;
case 'M':
case 'm':
$months = $interval->y * 12 + $interval->m;
if ($months) $output[] = sprintf("$of months", $months);
if ($length != 'l') break;
$interval->m = $interval->y = 0;
case 'D':
case 'd':
$days = ($interval->y * 12 + $interval->m) * 30 + $interval->d;
if ($days) $output[] = sprintf("$of days", $days);
if ($length != 'l') break;
$interval->d = $interval->m = $interval->y = 0;
case 'H':
case 'h':
$hours = (($interval->y * 12 + $interval->m) * 30 + $interval->d) * 24 + $interval->h;
if ($hours) $output[] = sprintf("$of hours", $hours);
if ($length != 'l') break;
$interval->h = $interval->d = $interval->m = $interval->y = 0;
case 'I':
case 'i':
$minutes = ((($interval->y * 12 + $interval->m) * 30 + $interval->d) * 24 + $interval->h) * 60 + $interval->i;
if ($minutes) $output[] = sprintf("$of minutes", $minutes);
if ($length != 'l') break;
$interval->i = $interval->h = $interval->d = $interval->m = $interval->y = 0;
case 'S':
case 's':
$seconds = (((($interval->y * 12 + $interval->m) * 30 + $interval->d) * 24 + $interval->h) * 60 + $interval->i) * 60 + $interval->s;
if ($seconds) $output[] = sprintf("$of seconds", $seconds);
break;
default:
return 'Invalid format';
break;
}
// put the output string together
$last = array_pop($output);
return $sign . (count($output) ? implode(', ', $output) . ' and ' : '') . $last;
}
用法示例:
echo friendlyDtmDiff('2020-02-28 00:00:00', '2020-03-01 12:00:56', '', 'h') . PHP_EOL;
echo friendlyDtmDiff('2020-02-28 00:00:00', '2020-03-01 12:00:56', 'l', 'h') . PHP_EOL;
echo friendlyDtmDiff('2020-02-28 00:00:00', '2020-03-01 12:08:56', 'l', 'h') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'y') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'm') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'd') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'h') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'i') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 's') . PHP_EOL;
输出:
60 hours
60 hours and 56 seconds
60 hours, 8 minutes and 56 seconds
1 years, 3 months, 14 days, 4 hours, 8 minutes and 56 seconds
15 months, 14 days, 4 hours, 8 minutes and 56 seconds
464 days, 4 hours, 8 minutes and 56 seconds
11140 hours, 8 minutes and 56 seconds
668408 minutes and 56 seconds
40104536 seconds
我正在尝试创建一个函数来找出两个日期时间之间的差异,但我希望能够 return 每个日期时间的绝对值。
说相差15分20秒,我希望能够输出15分,20秒,或者920秒。这也将扩展为数天、数月、数年。所以 2 天 12 分钟可能是 2 天、48 小时、2892 分钟或 173520 秒。
我最初是从我自己的代码开始的,但想在考虑天、月和年时考虑适当的差异,所以我改为使用 DateDiff,但我现在发现它不能按我想要的方式工作。
到目前为止,这是我的代码
define( 'MINUTE_IN_SECONDS', 60 );
define( 'HOUR_IN_SECONDS', 60 * MINUTE_IN_SECONDS );
define( 'DAY_IN_SECONDS', 24 * HOUR_IN_SECONDS );
define( 'WEEK_IN_SECONDS', 7 * DAY_IN_SECONDS );
define( 'MONTH_IN_SECONDS', 30 * DAY_IN_SECONDS );
define( 'YEAR_IN_SECONDS', 365 * DAY_IN_SECONDS );
/**
* Output a length between times in friendly format
*
* @param string $date1 Date/Time from in Y-m-d H:i:s format.
* @param string $date2 Date/Time to in Y-m-d H:i:s format.
* @param string $length Length of output. Set to "l" for detailed down to the second. Defaults to short if nothing entered.
* @param string $format Format to return the output in. Based on {@link https://www.php.net/manual/en/dateinterval.format.php PHP Date Interval Format}.
* If no format is set, the function will try assume the best output
*
* @return string Will return the requested output.
*/
function friendlyDtmDiff($date1, $date2, $length = '', $format = '') {
// Create DateTime for diff()
$dt1 = new \DateTime($date1);
$dt2 = new \DateTime($date2);
// Check if $dt2 ($date2) is before $dt1 ($date1) and
// swap the values if they are, also outputing a negative sign
if($dt2 < $dt1) {
$dtHolder = $dt1->format('Y-m-d H:i:s');
$dt1 = new \DateTime($dt2->format('Y-m-d H:i:s'));
$dt2 = new \DateTime($dtHolder);
$r = '-';
} else {
$r = '';
}
// Set the interval
$interval = $dt1->diff($dt2);
// Assume best output options
if(empty($format) || $format == '') {
// Difference in seconds
$diffSecs = $dt2->getTimestamp() - $dt1->getTimestamp();
if($diffSecs > YEAR_IN_SECONDS) { // Assume Years
$format = 'y';
} else if($diffSecs > MONTH_IN_SECONDS) { // Assume Months
$format = 'm';
} else if($diffSecs > DAY_IN_SECONDS) { // Assume Days
$format = 'd';
} else if($diffSecs > HOUR_IN_SECONDS) { // Assume Hours
$format = 'h';
} else if($diffSecs > MINUTE_IN_SECONDS) { // Assume Minutes
$format = 'i';
} else {// Assume seconds
$format = 's';
}
}
switch ($format) {
// Return seconds
case 's':
return $interval->format('%s seconds');
break;
// Return seconds padded
case 'S':
return $interval->format('%S seconds');
break;
// Return minutes
case 'i':
return ($length == 'l') ? $r . $interval->format('%i minutes and %s seconds') : $r . $interval->format('%i minutes') ;
break;
// Return minutes padded
case 'I':
return ($length == 'l') ? $r . $interval->format('%I minutes and %S seconds') : $r . $interval->format('%I minutes') ;
break;
// Return hours
case 'h':
return ($length == 'l') ? $r . $interval->format('%h hours, %i minutes, and %s seconds') : $r . $interval->format('%h hours') ;
break;
// Return hours padded
case 'H':
return ($length == 'l') ? $r . $interval->format('%H hours, %I minutes, and %S seconds') : $r . $interval->format('%H hours') ;
break;
// Return days
case 'a':
case 'd':
return ($length == 'l') ? $r . $interval->format('%d days, %h hours, %i minutes, and %s seconds') : $r . $interval->format('%d days') ;
break;
// Return days padded
case 'D':
return ($length == 'l') ? $r . $interval->format('%D days, %H hours, %I minutes, and %S seconds') : $r . $interval->format('%D days') ;
break;
// Return months
case 'm':
return ($length == 'l') ? $r . $interval->format('%m months, %d days, %h hours, %i minutes, and %s seconds') : $r . $interval->format('%m months') ;
break;
// Return months padded
case 'M':
return ($length == 'l') ? $r . $interval->format('%M months, %D days, %H hours, %I minutes, and %S seconds') : $r . $interval->format('%M months') ;
break;
default:
return 'not available';
break;
}
}
这是代码示例
$dtmNow = new \DateTime();
$authExpireDtm = new \DateTime();
$authExpireDtm->modify('+15 minutes');
echo friendlyDtmDiff($dtmNow->format('Y-m-d H:i:s'), $authExpireDtm->format('Y-m-d H:i:s'), 'l', 's');
我想输出900 seconds
,但它输出0 seconds
,这是$interval
有
DateInterval Object ( [y] => 0 [m] => 0 [d] => 0 [h] => 0 [i] => 15 [s] => 0 [f] => 0 [weekday] => 0 [weekday_behavior] => 0 [first_last_day_of] => 0 [invert] => 0 [days] => 0 [special_type] => 0 [special_amount] => 0 [have_weekday_relative] => 0 [have_special_relative] => 0 )
如您所见,s
项下没有任何内容(0
),所以我的功能当然是returning 0 seconds
。我想知道如何让它达到 return 900
秒。我知道比较时间(小时、分钟、秒)很容易,但我想在转换日、月、年时准确。
因此,如果我输入 2020-02-28 00:00:00
和 2020-03-01 00:00:00
,它将 return 172800 seconds
或 2880 minutes
,但如果我输入 2019-02-28 00:00:00
2019-03-01 00:00:00
它将 return 86400 seconds
或 1440 minutes
有谁能为我指明正确的方向以实现我想要的结果
这是一个可以完成您想要的 99% 的函数(它不会在 length != 'l'
时实现舍入,也不会从 1 years
中删除 s
).不输出 0 个值,尽管您可以添加一个参数来控制它。
function friendlyDtmDiff($date1, $date2, $length = '', $format = '') {
// Create DateTime for diff()
$dt1 = new \DateTime($date1);
$dt2 = new \DateTime($date2);
// Create intervals
if ($dt1 < $dt2) {
$sign = '';
$interval = $dt1->diff($dt2);
}
else {
$sign = '-';
$interval = $dt2->diff($dt1);
}
// Output format (minimum 2 digits for upper case formats)
$of = ($format < 'a') ? '%02d' : '%d';
// generate output using an array of terms to be imploded
$output = array();
// create time components
switch ($format) {
case 'Y':
case 'y':
$years = $interval->y;
if ($years) $output[] = sprintf("$of years", $years);
if ($length != 'l') break;
$interval->y = 0;
case 'M':
case 'm':
$months = $interval->y * 12 + $interval->m;
if ($months) $output[] = sprintf("$of months", $months);
if ($length != 'l') break;
$interval->m = $interval->y = 0;
case 'D':
case 'd':
$days = ($interval->y * 12 + $interval->m) * 30 + $interval->d;
if ($days) $output[] = sprintf("$of days", $days);
if ($length != 'l') break;
$interval->d = $interval->m = $interval->y = 0;
case 'H':
case 'h':
$hours = (($interval->y * 12 + $interval->m) * 30 + $interval->d) * 24 + $interval->h;
if ($hours) $output[] = sprintf("$of hours", $hours);
if ($length != 'l') break;
$interval->h = $interval->d = $interval->m = $interval->y = 0;
case 'I':
case 'i':
$minutes = ((($interval->y * 12 + $interval->m) * 30 + $interval->d) * 24 + $interval->h) * 60 + $interval->i;
if ($minutes) $output[] = sprintf("$of minutes", $minutes);
if ($length != 'l') break;
$interval->i = $interval->h = $interval->d = $interval->m = $interval->y = 0;
case 'S':
case 's':
$seconds = (((($interval->y * 12 + $interval->m) * 30 + $interval->d) * 24 + $interval->h) * 60 + $interval->i) * 60 + $interval->s;
if ($seconds) $output[] = sprintf("$of seconds", $seconds);
break;
default:
return 'Invalid format';
break;
}
// put the output string together
$last = array_pop($output);
return $sign . (count($output) ? implode(', ', $output) . ' and ' : '') . $last;
}
用法示例:
echo friendlyDtmDiff('2020-02-28 00:00:00', '2020-03-01 12:00:56', '', 'h') . PHP_EOL;
echo friendlyDtmDiff('2020-02-28 00:00:00', '2020-03-01 12:00:56', 'l', 'h') . PHP_EOL;
echo friendlyDtmDiff('2020-02-28 00:00:00', '2020-03-01 12:08:56', 'l', 'h') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'y') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'm') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'd') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'h') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 'i') . PHP_EOL;
echo friendlyDtmDiff('2018-12-28 00:00:00', '2020-04-11 04:08:56', 'l', 's') . PHP_EOL;
输出:
60 hours
60 hours and 56 seconds
60 hours, 8 minutes and 56 seconds
1 years, 3 months, 14 days, 4 hours, 8 minutes and 56 seconds
15 months, 14 days, 4 hours, 8 minutes and 56 seconds
464 days, 4 hours, 8 minutes and 56 seconds
11140 hours, 8 minutes and 56 seconds
668408 minutes and 56 seconds
40104536 seconds