PHP 5.1+ 重寫日期時間函數,若未設置時區,每次調用 date()、time() 等都會拋出 E_WARNING。本文詳解 date_default_timezone_set() 用法、中國時區標識符、運行時動態切換、框架集成與常見坑。
<?php
bool date_default_timezone_set(string $timezone_identifier): bool
成功返回 true,失敗(無效標識符)返回 false 並觸發警告。
<?php
// 推薦:IANA 時區數據庫標準格式
date_default_timezone_set('Asia/Shanghai'); // 亞洲/上海
date_default_timezone_set('Asia/Chongqing'); // 亞洲/重慶
date_default_timezone_set('PRC'); // 中華人民共和國(別名)
// 驗證
echo date_default_timezone_get(); // Asia/Shanghai
echo date('Y-m-d H:i:s'); // 正確輸出北京時間
建議: 統一使用 Asia/Shanghai,符合 IANA 標準,避免 PRC 未來可能棄用。
; php.ini
date.timezone = "Asia/Shanghai"
重啟 PHP-FPM 生效,全局生效,無需代碼修改。
<?php
// public/index.php 或 bootstrap/app.php 最頂部
date_default_timezone_set('Asia/Shanghai');
function getUserTime(User $user): DateTimeZone {
return new DateTimeZone($user->timezone ?? 'Asia/Shanghai');
}
// 顯示用戶本地時間
$dt = new DateTime('now', new DateTimeZone('Asia/Shanghai'));
$dt->setTimezone(getUserTime($user));
echo $dt->format('Y-m-d H:i:s');
<?php
// 創建帶時區的 DateTime
$dt = new DateTime('now', new DateTimeZone('Asia/Shanghai'));
echo $dt->format('Y-m-d H:i:s'); // 2024-01-15 14:30:00
// 時區轉換
$utc = new DateTime('now', new DateTimeZone('UTC'));
$shanghai = clone $utc;
$shanghai->setTimezone(new DateTimeZone('Asia/Shanghai'));
// 不可變版本 (PHP 5.5+)
$immutable = new DateTimeImmutable('now', new DateTimeZone('Asia/Shanghai'));
$later = $immutable->modify('+1 day'); // 返回新對象,原對象不變
時區 | 標識符
----------------------|-------------------
中國大陸/香港/澳門/台灣 | Asia/Shanghai, Asia/Hong_Kong, Asia/Macau, Asia/Taipei
美國東部 | America/New_York
美國西部 | America/Los_Angeles
英國/倫敦 | Europe/London
歐洲中部 | Europe/Berlin
日本/東京 | Asia/Tokyo
UTC | UTC
<?php
$zones = DateTimeZone::listIdentifiers(DateTimeZone::ALL);
foreach ($zones as $zone) {
if (stripos($zone, 'Asia') === 0) {
echo $zone . "\n";
}
}
| 現象 | 原因 | 解決 |
|---|---|---|
| date() 警告:It is not safe to rely on the system's timezone settings | 未設置 php.ini date.timezone 且代碼未調用 date_default_timezone_set | 設置 php.ini 或入口文件調用 |
| 時間相差 8 小時 | 服務器系統時區為 UTC,代碼未設置時區 | 同上 |
| DateTime 創建時區錯誤 | 字符串大小寫錯誤(如 asia/shanghai) | 嚴格按 IANA 大小寫:Asia/Shanghai |
| 夏令時導致時間跳變 | 使用了觀察夏令時的時區(如 America/New_York) | 業務層面決策:存儲 UTC,展示轉換 |
php -i | grep date.timezone 確認生效。TIMESTAMP (UTC) 或 DATETIME + 明確時區欄位。DateTimeZone 處理。