计算 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:002020-03-01 00:00:00,它将 return 172800 seconds2880 minutes,但如果我输入 2019-02-28 00:00:00 2019-03-01 00:00:00 它将 return 86400 seconds1440 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

Demo on 3v4l.org