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

发布于 2024-12-15 06:33:45 字数 336 浏览 1 评论 0原文

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

比如, 阿尼尔大约一个小时前玩了一场游戏。 阿尼尔两天前升级了。 阿尼尔刚刚发表了这条评论。

我知道可以使用一个小函数轻松完成,该函数计算旧时间与当前时间的差值,以秒(或毫秒)为单位并相应地返回一个字符串值。

我想问的是;

  1. 如何以最专业的方式完成?使用 PHP 计算时间差还是在查询时使用 SQL 计算时间差?
  2. 不会降低性能吗?想象一个有 100 条评论的页面,该函数将运行 100 次,因此,页面加载速度会变慢。

诗。我不是在寻找脚本。

Lately I have been facing websites with "X hours ago", "X days ago" features. (including stackoverflow)

Like,
Anil played a game around a hour ago.
Anil leveled up 2 days ago.
Anil posted this comment just now.

I know it can easily be done with a little function which calculates the old time to the current time, get difference in seconds (or miliseconds) and return a string value accordingly.

What I am trying to ask is;

  1. How can it be done at most professional way? Calculating time difference with PHP or get it calculated on our SQL while querying?
  2. Wouldn't it lower the performance? Imagine a page with 100 comments, the function will work 100 times, hence, the page will load slower.

Ps. I'm not looking for scripts.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

风筝有风,海豚有海 2024-12-22 06:33:45

通常的方法是使用普通的 SQL 查询来收集时间差作为整数,然后使用 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 次左右,您应该不会看到性能下降。

The usual approach is to use a normal SQL Query to gather the difference in time as an integer, and then convert it with PHP/Javascript. In other words, nothing fancy. Here is a PHP script used in most Twitter wrappers:

/**
* 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.';
  }
}
?>

This is generally so fast that it should take little time more than usual. If you have less than 300 or so calculations from this on a page you shouldn't see a performance drop.

吖咩 2024-12-22 06:33:45

我认为性能影响是可以忽略的。您也可以在客户端执行此操作,通过向客户端发送正常时间戳,例如,对于网络,有一个 jquery 插件可以执行此操作: jquery-timeago

我建议在客户端执行此操作,因为客户端可以根据需要刷新它(例如,当页面保持打开时间更长时)。如果需要的话,绝对数据也可供用户使用。

I think the performance implication is ignorable. Also you could do this on the client side, by sending normal timestamps to the client, e.g. for the web there is a jquery plugin that does this: jquery-timeago.

I would recommend to do this on the client side, because here the client can refresh it as wished (e.g. when the page stays open longer). Also the absolute data is available to the user, if needed.

趴在窗边数星星i 2024-12-22 06:33:45

从数据库中获取数据后,几乎可以肯定最好将其作为独立函数来执行。

当然,它会产生很小的开销……但是,当将该开销与您为渲染页面所做的所有其他操作的开销进行比较时,我预计它甚至无法测量(除非您的算法效率极低) )。

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

It would almost certainly be best to do as a standalone function after the data have been fetched from the database.

It will, of course, incur a small overhead… But when that overhead is compared to the overhead of everything else you're doing to render the page, I expect it won't even be possible to measure (unless your algorithm is incredibly inefficient).

Additionally, since the database is often the bottleneck, not the app server's CPU, it's generally a good idea to do this kind of work on the app server instead of the database.

在你怀里撒娇 2024-12-22 06:33:45

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 次调用将达到一毫秒的计算量。

100 times almost nothing is still almost nothing. Don't worry about it. One simple check as in:

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"

will only take you a few clock cycles. You will have 3 billion clock cycles at your disposal a second so a 100 calls to such a function would reach a millisecond of computational effort.

无敌元气妹 2024-12-22 06:33:45

在 sql 中,由于语言的原因,计算将花费你的时间来构建。
我的选择是 php 或 javascript。
我也听说过 jquery 解决这个问题的方法。
Javascript会将计算成本完全压给客户端。

In sql the calculation will cost you time to build because of the language.
the choice for me would be php or javascript.
I've also heard of jquery solutions for this problem.
Javascript would press the calculation cost entirely to the client.

以往的大感动 2024-12-22 06:33:45

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

你可以做的是在你的数据库中有一个时间戳(考虑一个中性时区),然后进行查询,以便你显示适合你的时间间隔的任何内容(即时间戳 - now() < N),其中 N 是你的时间间隔。

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

我不会将逻辑放入数据库的原因是因为我认为此类数据依赖于应用程序,而不是依赖于数据库 - IE 有一天您可能想以另一种方式显示时间差异,而数据库可能不是最通用的您手头拥有的工具 - 不一定是因为性能(我认为影响可以忽略不计)。

My suggestion goes to calculating differences with PHP.

What you could do is having a timestamp (consider a neutral timezone) in your db, and then make the query so that you dispay whatever fits your interval (IE timestamp - now() < N), where N is your time interval.

At that point, you use PHP to translate the event date to a difference from now (which could also be made dynamic client side - IE Javascript - for most recent entries, so to encompass seconds/minutes elapsed as ebay does with expiring actions).

The reason why I wouldn't put logic in the database is because I think that such data is application dependant, rather than db dependant - IE one day you might want to show time differences in another way, and db could not be the most versatile tool you have at hand - not necessarily because of performance (I think the impact can be neglegible anyways).

江心雾 2024-12-22 06:33:45
  1. 从 SQL 获取时间戳,
  2. 使用简单的减法来获取以秒为单位的差异,
  3. 您可以实现一个简单的 Ordo log(n) 函数,而不是 Ordo n,来获取文本延时,如下所示:
function niceTime($difference) {
  if ($difference > 86400)
    if ($difference > 2592000)
      if ($difference > 30758400) {
        $time = round($difference / 30758400);
        $unit = 'year';
      } else {
        $time = round($difference / 2592000);
        $unit = 'month';
      }
    else
      if ($difference > 604800) {
        $time = round($difference / 604800);
         $unit = 'week';
      } else {
        $time = round($difference / 86400);
        $unit = 'day';
      }
  else
    if ($difference > 900)
      if ($difference > 3600) {
        $time = round($difference / 3600);
        $unit = 'hour';
      } else {
        $time = round($difference / 900);
        $unit = 'quarter';
      }
    else
      if ($difference > 60) {
        $time = round($difference / 60);
        $unit = 'minute';
      } else {
        $time = round($difference);
        $unit = 'second';
      }
  return $time . ' ' . $unit . ($time != 1 ? 's' : '') . ' ago';
}

这里的想法是您应该不要迭代八个步骤来找出给定的差异确实是最坏的情况(一年多)。相反,你每次都将你的选择分成两半,并且在三次比较中你总是会到达“正确”的时间。

在最坏的情况下,如果您的页面有 100,000 条评论,而且都是两年前的评论,这会将比较次数从 800,000 减少到 300,000,这将是值得注意的。 ;-)

  1. get the timestamps from SQL,
  2. use simple subtraction to get the difference in seconds
  3. you can implement a simple Ordo log(n) function, rather than an Ordo n, to get the textual timelapse, like the following:
function niceTime($difference) {
  if ($difference > 86400)
    if ($difference > 2592000)
      if ($difference > 30758400) {
        $time = round($difference / 30758400);
        $unit = 'year';
      } else {
        $time = round($difference / 2592000);
        $unit = 'month';
      }
    else
      if ($difference > 604800) {
        $time = round($difference / 604800);
         $unit = 'week';
      } else {
        $time = round($difference / 86400);
        $unit = 'day';
      }
  else
    if ($difference > 900)
      if ($difference > 3600) {
        $time = round($difference / 3600);
        $unit = 'hour';
      } else {
        $time = round($difference / 900);
        $unit = 'quarter';
      }
    else
      if ($difference > 60) {
        $time = round($difference / 60);
        $unit = 'minute';
      } else {
        $time = round($difference);
        $unit = 'second';
      }
  return $time . ' ' . $unit . ($time != 1 ? 's' : '') . ' ago';
}

The idea here is that you shouldn't iterate through eight steps to find out that a given difference indeed was the worst case scenario (over a year). Rather you split your options in half every time, and you will allways arive at the "correct" time in three comparisons.

In the worst case scenario where you have a page with 100.000 comments that are all two years old, this will reduce the number of comparisons from 800.000 to 300.000, which will be noticable. ;-)

缺⑴份安定 2024-12-22 06:33:45

我更改了镰刀提供的代码,以添加月数、周数和年数的津贴。

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

I have altered the code provided by sickle to add allowance for number of months, number of weeks, and years.

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.';
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文