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

PHP 日期時間處理深度解析:時間戳、時區、格式化與 UCHome 實戰案例

     編輯:PHP 綜合知識

核心函式速查

函式用途回傳
time()當前 Unix 時間戳(秒)int
microtime(true)含微秒的浮點數時間戳float
mktime(h,i,s,m,d,y)指定日期時間轉時間戳int/false
strtotime('+1 day')相對/絕對時間字串轉時間戳int/false
date('Y-m-d H:i:s', $ts)依預設時區格式化string
gmdate('Y-m-d H:i:s', $ts)依 UTC 格式化string
strftime('%Y-%m-%d', $ts)區域化格式化(依 setlocale)string
getdate($ts)回傳結構化陣列array
DateTime 物件現代 OO 介面(PHP 5.2+)object

時區陷阱與實測

<?php
date_default_timezone_set('Asia/Taipei'); // 必須設定,否則發 E_WARNING

$ts = strtotime('2024-01-15 12:00:00'); // 解析為當前時區時間
echo "date:    " . date('H:i', $ts) . "\n";    // 12:00 (本地)
echo "gmdate:  " . gmdate('H:i', $ts) . "\n";  // 04:00 (UTC)
echo "差異: " . (date('H', $ts) - gmdate('H', $ts)) . " 小時\n"; // 8

// 1970-01-01 00:00:00 UTC 在台北是 08:00
echo mktime(0,0,0,1,1,1970); // -28800 (=-8*3600)
?>

關鍵: time()/mktime() 回傳的永遠是 UTC 時間戳(自 1970-01-01 00:00:00 UTC 起算秒數)。date() 會套用預設時區顯示,gmdate() 則直接顯示 UTC。

UChome 風格相對時間函式分析

<?php
/**
 * 參考 UChome sgmdate:顯示相對時間(幾秒前、幾分鐘前、幾小時前)或完整日期
 */
function formatRelativeTime(int $timestamp, string $format = 'Y-m-d H:i'): string
{
    $now = time();
    $diff = $now - $timestamp;

    if ($diff < 0) $diff = 0; // 未來時間視為剛剛

    if ($diff < 60) {
        return "$diff 秒前";
    } elseif ($diff < 3600) {
        return floor($diff / 60) . " 分鐘前";
    } elseif ($diff < 86400) {
        return floor($diff / 3600) . " 小時前";
    } elseif ($diff < 604800) {
        return floor($diff / 86400) . " 天前";
    } else {
        return date($format, $timestamp);
    }
}

// 測試
echo formatRelativeTime(time() - 30) . "\n";      // 30 秒前
echo formatRelativeTime(time() - 3600) . "\n";    // 1 小時前
echo formatRelativeTime(strtotime('-10 days')) . "\n"; // 2024-01-05 12:00
?>

UChome 時區修正邏輯解析

原始碼片段:

<?php
function sstrtotime($string) {
    global $_SGLOBAL, $_SCONFIG;
    $time = strtotime($string);
    // 檢測系統時區設定是否正確
    if (gmdate('H:i', $_SGLOBAL['timestamp'] + $_SCONFIG['timeoffset'] * 3600) != date('H:i', $_SGLOBAL['timestamp'])) {
        // 系統時區錯誤,手動修正
        $time -= $_SCONFIG['timeoffset'] * 3600;
    }
    return $time;
}
?>

邏輯: 比較「UTC 時間戳 + 設定偏移」經 gmdate 格式化 vs 直接 date 格式化。若不一致,表示 PHP 內建時區資料庫與系統設定不符,需手動扣除偏移量。現代 PHP (5.1+) 強制要求 date.timezone 設定,此修正碼多為歷史遺留相容。

現代最佳實踐:DateTime + DateTimeZone

<?php
// 建立指定時區的日期時間
$dt = new DateTime('2024-01-15 12:00:00', new DateTimeZone('Asia/Taipei'));
echo $dt->format('Y-m-d H:i:s P'); // 2024-01-15 12:00:00 +08:00

// 轉換時區
$dt->setTimezone(new DateTimeZone('UTC'));
echo $dt->format('Y-m-d H:i:s P'); // 2024-01-15 04:00:00 +00:00

// 相對運算
$dt->modify('+1 month -3 days');
echo $dt->format('Y-m-d');

// 計算差異
$diff = $dt->diff(new DateTime('now'));
echo $diff->format('%a 天 %h 小時 %i 分鐘');

// 格式化區域化(需安裝 intl 擴展)
$fmt = new IntlDateFormatter('zh_TW', IntlDateFormatter::LONG, IntlDateFormatter::NONE, 'Asia/Taipei');
echo $fmt->format($dt); // 2024年1月15日 星期一 上午12時00分
?>

常見坑點彙整

  • strtotime('now') vs time(): 前者受 date.timezone 影響解析「當地現在」,後者永遠回傳 UTC 時間戳,兩者數值相同但語意不同。
  • 夏令時間: DateTimeZone 內建 IANA 時區資料庫自動處理,date() + 手動偏移量無法正確處理 DST 切換。
  • 32 位元系統 2038 年問題: 整數時間戳上限 2038-01-19,務必使用 64 位元 PHP 或 DateTime 物件。
  • 資料庫儲存: 推薦 TIMESTAMP(自動 UTC 轉換)或 DATETIME + 應用層統一 UTC 存儲。

結語

日期時間處理的核心是時區感知。棄用 date()/gmdate() + 手動偏移的舊模式,全面擁抱 DateTime、DateTimeZone、IntlDateFormatter,並統一應用層、資料庫層、日誌層使用 UTC,只在顯示層轉換使用者時區,才能避開時區地雷區。

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