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

JS + PHP 實現用戶本地時間顯示:時區偏移獲取、夏令時判斷與服務端轉換全流程

     編輯:PHP 相關知識

業務背景

跨時區應用中,服務器統一存儲 GMT/UTC 時間,客戶端需根據用戶所在時區動態顯示本地時間。本文提供一套「前端檢測 → Cookie 傳遞 → 後端轉換」的完整方案。

前端 JavaScript 實現

<script>
window.onload = function() {
    // 1. 獲取時區偏移(小時),東區為正,西區為負
    var exp = new Date();
    var gmtHours = -(exp.getTimezoneOffset() / 60); // getTimezoneOffset 返回分鐘差(UTC - 本地)
    setCookie('customer_timezone', gmtHours, 1);    // 存儲 1 天

    // 2. 判斷夏令時
    var dateStr = formatDate(exp, 'yyyy-MM-dd HH:mm:ss');
    if (inDaylightTime(dateStr)) {
        setCookie('inDaylightTime', 1, 1);
    }
};

// 格式化日期輔助
function formatDate(date, fmt) {
    var o = {
        "M+": date.getMonth() + 1,
        "d+": date.getDate(),
        "H+": date.getHours(),
        "m+": date.getMinutes(),
        "s+": date.getSeconds()
    };
    for (var k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (o[k] < 10 ? "0" : "") + o[k]);
    return fmt.replace(/(y+)/, date.getFullYear());
}

// 設置 Cookie
function setCookie(name, value, days) {
    var exp = new Date();
    exp.setDate(exp.getDate() + days);
    document.cookie = name + "=" + escape(value) + "; expires=" + exp.toGMTString() + "; path=/";
}

// 判斷東/西半球
function isEastEarthTime(date) {
    var offset = date.getTimezoneOffset(); // 分鐘
    return offset <= 0; // 東區 offset 為負或零
}

// 夏令時判斷邏輯:對比年初與年中時區偏移
function inDaylightTime(dateStr) {
    var date = new Date(dateStr);
    var jan = new Date(date.getFullYear(), 0, 1);
    var jul = new Date(date.getFullYear(), 6, 1);
    var janOffset = jan.getTimezoneOffset();
    var julOffset = jul.getTimezoneOffset();
    if (janOffset === julOffset) return false; // 無夏令時
    var stdOffset = isEastEarthTime(date) ? julOffset : janOffset; // 標準時間偏移
    return date.getTimezoneOffset() !== stdOffset; // 當前偏移 ≠ 標準偏移即為夏令時
}
</script>

後端 PHP 轉換

<?php
/**
 * GMT 時間戳轉換為用戶本地時間(僅返回 H:i)
 * @param int|string $time GMT 時間戳
 * @param bool $dst 是否強制夏令時(由 Cookie 決定)
 * @return string 格式化後的本地時間
 */
function gmt_to_local($time = '', $dst = false) {
    if ($time === '') return date('H:i'); // 默認當前時間

    // 1. 讀取時區偏移
    $timezone = isset($_COOKIE['customer_timezone']) ? floatval($_COOKIE['customer_timezone']) : 0;

    // 2. 基礎偏移轉換
    $time += $timezone * 3600;

    // 3. 夏令時額外 +1 小時
    if (isset($_COOKIE['inDaylightTime']) && $_COOKIE['inDaylightTime'] == '1') {
        $dst = true;
    }
    if ($dst) $time += 3600;

    return date('H:i', $time);
}

// 使用示例
$gmtTime = strtotime('2024-01-01 12:00:00'); // 假設數據庫存儲的 GMT 時間
echo "用戶本地時間: " . gmt_to_local($gmtTime);
?>

方案優缺點與改進

優點缺點/風險
純前端檢測,無需用戶手動選擇時區依賴 Cookie,用戶禁用 Cookie 則失效
夏令時自動判斷,無需維護時區數據庫JS 夏令時判斷邏較簡略,極少數地區規則特殊可能誤判
服務端無狀態,易於擴展首次訪問無 Cookie 時默認 GMT,體驗不佳

現代最佳實踐建議

  1. 首選 IANA 時區標識符:前端使用 Intl.DateTimeFormat().resolvedOptions().timeZone 獲取如 Asia/Shanghai,傳給後端。
  2. 後端使用 DateTimeZone:new DateTime('@'.$timestamp, new DateTimeZone($tz))->format('Y-m-d H:i'),自動處理夏令時、歷史規則變更。
  3. 存儲用戶偏好:將用戶選擇/檢測到的時區保存至用戶表,不依賴 Cookie。
  4. 前端渲染:傳遞 UTC 時間戳給前端,由 JS (或 Moment.js, Day.js, Luxon) 實時格式化,減輕後端壓力並支持實時更新。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved