“大约一小时前”;PHP / SQL中的逻辑以及它如何影响性能


"About a hour ago" logic in PHP / SQL and how it affects performance?

最近我一直在面对带有"X小时前","X天前"功能的网站。(包括stackoverflow)

,阿尼尔一小时前玩了一场游戏。阿尼尔2天前升级了。阿尼尔刚刚发了这条评论

我知道它可以很容易地完成一个小函数,计算旧时间到当前时间,得到秒(或毫秒)的差异,并返回相应的字符串值。

我想问的是;

  1. 怎样才能做到最专业?计算时差与PHP或得到它计算在我们的SQL而查询?
  2. 这不会降低性能吗?想象一个有100条评论的页面,这个函数将工作100次,因此,页面加载速度会变慢。

p。我不是在找剧本。

通常的方法是使用普通的SQL Query将时间差收集为整数,然后使用PHP/Javascript进行转换。换句话说,没什么特别的。下面是大多数Twitter包装器中使用的PHP脚本:

/**
* Formats a timestamp nicely with an adaptive "x units of time ago" message.
* Based on the original Twitter JavaScript badge. Only handles past dates.
* @return string Nicely-formatted message for the timestamp.
* @param $time Output of strtotime() on your choice of timestamp.
*/
function niceTime($time) {
  $delta = time() - $time;
  if ($delta < 60) {
    return 'less than a minute ago.';
  } else if ($delta < 120) {
    return 'about a minute ago.';
  } else if ($delta < (45 * 60)) {
    return floor($delta / 60) . ' minutes ago.';
  } else if ($delta < (90 * 60)) {
    return 'about an hour ago.';
  } else if ($delta < (24 * 60 * 60)) {
    return 'about ' . floor($delta / 3600) . ' hours ago.';
  } else if ($delta < (48 * 60 * 60)) {
    return '1 day ago.';
  } else {
    return floor($delta / 86400) . ' days ago.';
  }
}
?>

这通常是如此之快,应该比平时多花一点时间。如果您在一个页面上的计算少于300次左右,您应该不会看到性能下降。

我认为性能影响是可以忽略不计的。你也可以在客户端做到这一点,通过发送正常的时间戳到客户端,例如,对于web有一个jquery插件这样做:jquery-timeago .

我建议在客户端这样做,因为在这里客户端可以刷新它(例如,当页面保持打开更长时间)。如果需要,绝对数据也可以提供给用户。

最好是在从数据库中获取数据后作为一个独立的函数。

当然,它会产生一个小的开销…但是当这个开销与你所做的渲染页面的其他开销相比,我希望它甚至无法测量(除非你的算法非常低效)。

此外,由于数据库通常是瓶颈,而不是应用服务器的CPU,因此在应用服务器上而不是数据库上执行此类工作通常是一个好主意。

100次几乎什么都没有还是几乎什么都没有。别担心。一个简单的检查,如:

if time > day
  write time.in_days + " days"
if time > hour
  write time.in_hours + " hours"
if time > minute
  write time.in_minutes + " minute"
if time > second
  write time.in_seconds + " seconds"
if time > millisecond
  write time.in_seconds + " milliseconds"

只需要几个时钟周期。你每秒将有30亿个时钟周期供你支配,所以对这样一个函数的100次调用将达到一毫秒的计算工作量。

在sql中,由于语言的原因,计算将花费您时间来构建。我的选择是PHP还是javascript。我也听说过针对这个问题的jquery解决方案。Javascript将把计算成本完全推给客户端。

我的建议是计算与PHP的差异。

你可以做的是在你的数据库中有一个时间戳(考虑一个中立的时区),然后进行查询,这样你就可以显示任何适合你的间隔(IE timestamp - now() <N),其中N为您的时间间隔。>

此时,您可以使用PHP将事件日期转换为与现在不同的日期(对于最近的条目,也可以动态客户端- IE Javascript,以便包含经过的秒/分钟,就像ebay处理过期操作一样)。

我不把逻辑放在数据库中的原因是因为我认为这些数据是应用程序依赖的,而不是数据库依赖的- IE有一天你可能想要用另一种方式显示时间差,而db可能不是你手头上最通用的工具-不一定是因为性能(我认为影响可以忽略不计)。

  1. 从SQL获取时间戳,
  2. 使用简单的减法来获得秒差
  3. 您可以实现一个简单的Ordo log(n)函数,而不是Ordo n,以获得文本时间间隔,如下所示:
<>之前函数niceTime($difference) {If ($difference> 86400)If ($difference> 2592000)If ($difference> 30758400) {$time = round($difference/30758400);$unit = 'year';} else {$time = round($difference/2592000);$unit = 'month';}其他的If ($difference> 604800) {$time = round($difference/604800);$unit = '周';} else {$time = round($difference/86400);$unit = 'day';}其他的If ($difference> 900)如果($difference> 3600) {$time = round($difference/3600);$unit = '小时';} else {$time = round($difference/900);$unit = 'quarter';}其他的If ($difference> 60) {$time = round($difference/60);$unit = 'minute';} else {$time = round($difference);$unit = 'second';}返回$time。’"。美元的单位。$time = 1 ?'s': ')。"前";}之前

这里的想法是,您不应该重复执行八个步骤来找出给定的差异确实是最坏的情况(超过一年)。相反,你每次都把你的选择分成两半,你总是会在三次比较中得到"正确"的时间。

在最坏的情况下,您的页面有100,000条评论,这些评论都是两年前的,这将减少比较的数量,从800,000到300,000,是明显的。-)

我修改了由sickle提供的代码,以添加月数、周数和年。

function agoTime($time) {
$delta = time() - $time;
if ($delta < 60) {
  return 'less than a minute ago.';
 } else if ($delta < 120) {
return 'about a minute ago.';
 } else if ($delta < (45 * 60)) {
return floor($delta / 60) . ' minutes ago.';
 } else if ($delta < (90 * 60)) {
return 'about an hour ago.';
 } else if ($delta < (24 * 60 * 60)) {
return 'about ' . floor($delta / 3600) . ' hours ago.';
 } else if ($delta < (48 * 60 * 60)) {
return '1 day ago.';
 } else if ($delta < (11 * 24 * 60 * 60)) {
return 'about a week ago.';
 } else if ($delta < (30 * 24 * 60 * 60)) {
return 'about ' .floor($delta / 604800) . ' weeks ago.';
 } else if ($delta < (45 * 24 * 60 * 60)) {
return 'more than a month ago.';
 } else if ($delta < (365 * 24 * 60 * 60)) {
return 'about ' .floor($delta / 2592000) . ' months ago.';
 } else if ($delta < (550 * 24 * 60 * 60)) {
return 'more than a year ago.';
 } else {
return 'about ' .floor($delta / 31536000) . ' years ago.';
 }