社群、論壇、動態牆常需顯示「3 分鐘前」、「2 天前」而非絕對時間。本文提供支援多語系、可擴充閾值的相對時間函式。
<?php
function time_ago(DateTimeInterface|string|int $time, string $locale = 'zh_TW'): string {
$now = new DateTime();
$then = $time instanceof DateTimeInterface
? clone $time
: (is_int($time) ? (new DateTime())->setTimestamp($time) : new DateTime($time));
$diff = $now->getTimestamp() - $then->getTimestamp();
if ($diff < 0) $diff = 0; // 未來時間視為剛剛
$intervals = [
'year' => 31556926, // 365.25 天
'month' => 2629743, // 30.44 天
'week' => 604800,
'day' => 86400,
'hour' => 3600,
'minute' => 60,
'second' => 1,
];
$labels = [
'zh_TW' => [
'year' => ['年', '年前'], 'month' => ['個月', '個月前'],
'week' => ['週', '週前'], 'day' => ['天', '天前'],
'hour' => ['小時', '小時前'], 'minute' => ['分鐘', '分鐘前'],
'second' => ['秒', '秒前'], 'just_now' => '剛剛',
],
'en' => [
'year' => ['year', 'years ago'], 'month' => ['month', 'months ago'],
'week' => ['week', 'weeks ago'], 'day' => ['day', 'days ago'],
'hour' => ['hour', 'hours ago'], 'minute' => ['minute', 'minutes ago'],
'second' => ['second', 'seconds ago'], 'just_now' => 'just now',
],
];
$lang = $labels[$locale] ?? $labels['en'];
foreach ($intervals as $unit => $seconds) {
$count = floor($diff / $seconds);
if ($count >= 1) {
$label = $count === 1 ? $lang[$unit][0] : $lang[$unit][1];
return $count . $label;
}
}
return $lang['just_now'];
}
// 使用範例
echo time_ago('-5 minutes'); // 5分鐘前
echo time_ago('-2 hours'); // 2小時前
echo time_ago('-3 days'); // 3天前
echo time_ago('-1 week'); // 1週前
echo time_ago('2024-01-01'); // 幾個月前
echo time_ago(time() - 30); // 30秒前
echo time_ago(time()); // 剛剛
?>
function time_diff(DateTimeInterface|string|int $from, DateTimeInterface|string|int $to = null, string $locale = 'zh_TW'): string {
$from = $from instanceof DateTimeInterface ? clone $from : (is_int($from) ? (new DateTime())->setTimestamp($from) : new DateTime($from));
$to = $to ?? new DateTime();
$to = $to instanceof DateTimeInterface ? clone $to : (is_int($to) ? (new DateTime())->setTimestamp($to) : new DateTime($to));
$diff = $to->getTimestamp() - $from->getTimestamp();
$past = $diff >= 0;
$diff = abs($diff);
// ... 同 time_ago 邏輯 ...
$suffix = $past ? '前' : '後';
return $count . $lang[$unit][0] . $suffix;
}
// 在迴圈中重用 DateTime
$now = new DateTime();
foreach ($posts as $post) {
$postTime = DateTime::createFromFormat('U', $post['created_at']);
$diff = $now->getTimestamp() - $postTime->getTimestamp();
// ...
}
<time class="timeago" datetime="2024-01-15T14:30:00+08:00">2024-01-15 14:30</time>
<script src="https://cdn.jsdelivr.net/npm/timeago.js@4"></script>
<script> timeago().render(document.querySelectorAll('.timeago')); </script>
優點:瀏覽器自動更新、支援 40+ 語系、無伺服器負擔。缺點:需前端渲染、SEO 需輸出 datetime 屬性。
-- MySQL 直接算相對秒數 SELECT UNIX_TIMESTAMP() - UNIX_TIMESTAMP(created_at) AS diff_seconds FROM posts;
減少 PHP 端物件建立開銷,大量列表顯示時效能顯著提升。