跨時區應用中,伺服器儲存 GMT 時間,客戶端需依所在時區顯示當地時間。本文提供一套前後端配合方案:前端 JS 偵測時區與夏令時,寫入 Cookie;後端 PHP 讀取 Cookie 進行時間轉換。
window.onload = function() {
// 取得用戶與 GMT 時差(小時)
var exp = new Date();
var gmtHours = -(exp.getTimezoneOffset() / 60);
setCookie('customer_timezone', gmtHours, 1);
// 判斷是否為夏令時
var date = exp.format('yyyy-MM-dd HH:mm:ss'); // 需自行擴充 Date.prototype.format
if (inDaylightTime(date)) {
setCookie('inDaylightTime', 1, 1);
}
};
// 設定 Cookie
function setCookie(c_name, value, expiredays) {
var exdate = new Date();
exdate.setDate(exdate.getDate() + expiredays);
document.cookie = c_name + "=" + escape(value) +
((expiredays == null) ? "" : "; expires=" + exdate.toGMTString());
}
// 判斷東/西半球
function isEastEarthTime(newDate) {
var dj = newDate.getGMTOffset(false); // 需自行實作 getGMTOffset
return dj.indexOf("-") === -1;
}
// 判斷夏令時
function inDaylightTime(date) {
var start = new Date(date.getTime());
start.setMonth(0); start.setDate(1);
start.setHours(0); start.setMinutes(0); start.setSeconds(0);
var middle = new Date(start.getTime());
middle.setMonth(6); // 7 月
// 年初與年中時差相同,視為無夏令時
if ((middle.getTimezoneOffset() - start.getTimezoneOffset()) === 0) {
return false;
}
var margin = isEastEarthTime(date) ? middle.getTimezoneOffset() : start.getTimezoneOffset();
return date.getTimezoneOffset() === margin;
}
補充:上述代碼使用了 Date.prototype.format 與 getGMTOffset,需自行引入對應擴充庫(如 date.js)或自行實作。
// 24 小時內 GMT 轉本地時間
function gmt_to_local($time = '', $dst = FALSE) {
// 讀取 JS 寫入的 Cookie
$timezone = isset($_COOKIE["customer_timezone"]) ? (int)$_COOKIE["customer_timezone"] : 0;
if ($time === '') { return date("H:i"); } // 若無傳入時間,回傳當前時間
// 時區偏移換算(秒)
$time += $timezone * 3600;
// 夏令時額外 +1 小時
if (isset($_COOKIE["inDaylightTime"]) && $_COOKIE["inDaylightTime"] == 1) {
$dst = TRUE;
}
if ($dst === TRUE) {
$time += 3600;
}
return date("H:i", $time);
}
onload 觸發 JS 偵測時區與夏令時,寫入 Cookie(有效期 1 天)。