格式化具有最小差异的日期时间间隔

Format datetime interval with a minimum difference

found 这个非常好的 PHP 脚本可以将任何日期时间转换成相对字符串,例如:

'2013-05-01 00:22:35'  ->  '3 months ago'

这真的很酷,但我想 "trick" 这个函数,这样即使日期是,比方说,20 分钟前,函数 returns 1 hour ago 而不是20 minutes ago。因此,我想强制执行 1 小时的最小差异,即使差异小于 1 小时。

作为参考,这里是函数。

function time_elapsed_string($datetime, $full = false) {
  $now = new DateTime;
  $ago = new DateTime($datetime);
  $diff = $now->diff($ago);

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

我尝试了很多不同的方法,但没有任何效果。

如何强制执行 1 小时的最小差异?

days :如果 DateInterval 对象是由 DateTime::diff() 创建的,则这是开始日期和结束日期之间的总天数。否则,days 将为 FALSE。 http://php.net/manual/en/class.dateinterval.php

因为我们知道它不会为 false,所以只有当为 0 时它才会计算为 false。

if($diff->days) {
    $diff->w = floor($diff->d / 7);
    $diff->d -= $diff->w * 7;
} else /* less than a day's difference */ if(!$diff->h && ($diff->i || $diff->s)) /* less than an hour's difference */ {
    $diff->h = 1;
    $diff->i = 0;
    $diff->s = 0;
}

找出差异后,只需检查最大差异是否只有分钟或秒。如果是这样,return 您需要的最少 1 小时。

// here is your foreach loop

// check if less than 1 hour, if so, return that
$keys = array_keys($string);
if ($keys[0] === 'i' || $keys[0] === 's') {
  return 'less than 1 hour ago';
}

Try it online!
我把发题时间放在这个例子里。当您在 1 个多小时后查看它时,您必须将测试用例修改为 UTC 时间小于 1 小时前的 DateTime。

测试用例。 现在是 2017-06-10 12:45:00 UTC。

time_elapsed_string("2017-06-10 12:11:19"); // less than 1 hour ago
time_elapsed_string("2017-06-10 11:44:00"); // 1 hour ago
time_elapsed_string("2017-06-10 11:44:00", true); // 1 hour, 1 minute ago
time_elapsed_string("2017-06-09 11:45:00", true); // 1 day, 1 hour ago
time_elapsed_string("2017-06-09 11:45:00"); // 1 day ago

我对您的原始代码进行了一些改进。我还从您的函数中删除了 full 选项,因为我认为您不打算将它用于您的案例。如果我的内联评论无法解释我的过程,请问。

代码:(Demo)

function time_elapsed_string($datetime){
    $now=new DateTime;  // current datetime
    $ago=new DateTime($datetime);  // user datetime
    if($now<$ago){return "Unexpected future datetime value";}
    $diff=$now->diff($ago);  // datetime difference
    $diff->w=intval(floor($diff->d/7));  // add weeks to diff output
    $diff->d-=$diff->w*7;  // reduce days based on weeks calculation
    $units=[
        'y'=>'year',
        'm'=>'month',
        'w'=>'week',
        'd'=>'day',
        'h'=>'hour'
    ];
    $kept_diff=array_intersect_key((array)$diff,$units);  // omit unwanted elements of diff()'s output
    if(!max($kept_diff)){  // if y, m, w, d, & h all = 0, show default
        return 'default: 1 hour ago';  // inserted "default: " for demo.  Remove in production.
    }else{
        $diffs=array_filter(array_merge($units,$kept_diff)); // sort by $units order, then omit elements with 0 value
        return current($diffs).' '.$units[key($diffs)].(current($diffs)>1?'s':'').' ago'; // return highest unit data in plain English
    }
}
echo time_elapsed_string('2017-06-30 02:22:35');  // output: 3 weeks ago