首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 實現友好時間顯示 (幾秒前、幾分鐘前、昨天、前天...) 完整代碼

     編輯:PHP 綜合知識

前言

類似微博、微信的相對時間顯示 (「3分鐘前」、「昨天 10:23」) 能顯著提升用戶體驗。本文提供生產就緒的 PHP 實現,含邊界處理、時區支援、擴展建議。

核心實現

<?php
/**
 * 格式化友好相對時間
 * @param int $timestamp Unix 時間戳
 * @param string $timezone 時區 (預設 UTC)
 * @return string
 */
function friendly_time($timestamp, $timezone = 'UTC') {
    // 時區處理
    date_default_timezone_set($timezone);
    $now = time();
    
    // 修正未來時間
    if ($timestamp > $now) $timestamp = $now;
    
    $diff = $now - $timestamp;
    
    // 1. 一分鐘內
    if ($diff < 60) {
        return $diff . '秒前';
    }
    
    // 2. 一小時內
    if ($diff < 3600) {
        return floor($diff / 60) . '分鐘前';
    }
    
    // 3. 今日內 (超過 1 小時)
    $todayStart = strtotime('today');
    if ($timestamp >= $todayStart) {
        return floor($diff / 3600) . '小時前';
    }
    
    // 4. 昨天
    $yesterdayStart = strtotime('yesterday');
    if ($timestamp >= $yesterdayStart) {
        return '昨天 ' . date('H:i', $timestamp);
    }
    
    // 5. 前天
    $beforeYesterdayStart = strtotime('day before yesterday');
    if ($timestamp >= $beforeYesterdayStart) {
        return '前天 ' . date('H:i', $timestamp);
    }
    
    // 6. 今年內 (超過 3 天)
    $yearStart = strtotime('January 1');
    if ($timestamp >= $yearStart) {
        return date('m月d日 H:i', $timestamp);
    }
    
    // 7. 更早
    return date('Y年m月d日 H:i', $timestamp);
}

// 使用範例
echo friendly_time(strtotime('-30 seconds'));      // 30秒前
echo friendly_time(strtotime('-45 minutes'));      // 45分鐘前
echo friendly_time(strtotime('-3 hours'));         // 3小時前
echo friendly_time(strtotime('yesterday 14:30'));  // 昨天 14:30
echo friendly_time(strtotime('2 days ago 09:15')); // 前天 09:15
echo friendly_time(strtotime('2023-05-20 10:00')); // 05月20日 10:00
echo friendly_time(strtotime('2020-01-01 00:00')); // 2020年01月01日 00:00

進階版:支援多語言與精確控制

class TimeFormatter {
    private $locale = 'zh_CN';
    
    public function __construct($locale = 'zh_CN') {
        $this->locale = $locale;
    }
    
    public function format($timestamp, $options = []) {
        $now = time();
        $diff = $now - $timestamp;
        
        $thresholds = [
            'just_now'   => 5,           // 幾秒內顯示"剛剛"
            'seconds'    => 60,
            'minutes'    => 3600,
            'hours'      => 86400,       // 1天
            'yesterday'  => 172800,      // 2天
            'days'       => 604800,      // 7天
            'weeks'      => 2592000,     // 30天
        ];
        
        if ($diff < $thresholds['just_now']) {
            return $this->t('just_now');
        }
        if ($diff < $thresholds['seconds']) {
            return $this->plural($diff, 'seconds');
        }
        if ($diff < $thresholds['minutes']) {
            return $this->plural(floor($diff/60), 'minutes');
        }
        if ($diff < $thresholds['hours']) {
            return $this->plural(floor($diff/3600), 'hours');
        }
        if ($diff < $thresholds['yesterday']) {
            return $this->t('yesterday') . ' ' . date('H:i', $timestamp);
        }
        if ($diff < $thresholds['days']) {
            return $this->plural(floor($diff/86400), 'days');
        }
        if ($diff < $thresholds['weeks']) {
            return $this->plural(floor($diff/604800), 'weeks');
        }
        
        // 超過閾值顯示完整日期
        return date($options['format'] ?? 'Y-m-d H:i', $timestamp);
    }
    
    private function plural($count, $unit) {
        $map = [
            'zh_CN' => ['seconds'=>'%d秒前', 'minutes'=>'%d分鐘前', 'hours'=>'%d小時前', 'days'=>'%d天前', 'weeks'=>'%d周前'],
            'en_US' => ['seconds'=>'%d sec ago', 'minutes'=>'%d min ago', 'hours'=>'%d hours ago', 'days'=>'%d days ago', 'weeks'=>'%d weeks ago'],
        ];
        return sprintf($map[$this->locale][$unit] ?? $map['zh_CN'][$unit], $count);
    }
    
    private function t($key) {
        $map = ['zh_CN'=>['just_now'=>'剛剛', 'yesterday'=>'昨天'], 'en_US'=>['just_now'=>'just now', 'yesterday'=>'yesterday']];
        return $map[$this->locale][$key] ?? $key;
    }
}

前端優化:JavaScript 實時更新

<!-- HTML -->
<time class="friendly-time" data-timestamp="1699833600">載入中...</time>

<script>
// 頁面載入後每分鐘更新一次
document.querySelectorAll('.friendly-time').forEach(el => {
    const ts = parseInt(el.dataset.timestamp);
    const update = () => {
        const diff = Math.floor(Date.now()/1000) - ts;
        let text = '';
        if (diff < 60) text = diff + '秒前';
        else if (diff < 3600) text = Math.floor(diff/60) + '分鐘前';
        else if (diff < 86400) text = Math.floor(diff/3600) + '小時前';
        else text = new Date(ts*1000).toLocaleString();
        el.textContent = text;
    };
    update();
    setInterval(update, 60000);
});
</script>

常見坑點與解決

問題解決
時區不一致統一用 UTC 存儲,顯示時按用戶時區轉換
未來時間顯示異常修正 $timestamp = min($timestamp, time())
閏秒/夏令時使用 DateTime/DateTimeZone 類處理複雜時區
緩存導致時間不更新前端 JS 實時更新或緩存鍵包含時間版本

總結

友好時間顯示核心邏輯簡單,關鍵在於邊界條件處理、時區統一、前端實時更新。建議封裝為工具類,配合前端 JS 實現最佳體驗。國際化專案可引入 IntlRelativeTimeFormat (JS) 或 PHP DateInterval 進階格式化。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved