問題現象
date()、time()、DateTime 輸出時間與預期相差數小時(通常相差 8 小時,因預設 UTC)。
三種設定層級(優先級遞增)
| 層級 | 方法 | 範圍 | 優先級 |
| 1. 腳本級 | date_default_timezone_set('Asia/Taipei') | 單一腳本執行期間 | 最高 |
| 2. 應用級 | 框架啟動檔/入口檔統一設定 | 整個應用生命週期 | 中 |
| 3. 系統級 | php.ini: date.timezone = Asia/Taipei | 所有 PHP 進程 | 最低(但最穩健) |
完整設定步驟
方法一:php.ini(推薦,一勞永逸)
- 定位
php.ini:php --ini 或 phpinfo() 查看 Loaded Configuration File
- 搜尋
[Date] 區段
- 修改:
; Defines the default timezone used by the date functions
date.timezone = Asia/Taipei
- 重啟 PHP-FPM/Apache:
systemctl reload php-fpm / apachectl graceful
方法二:腳本頂端(快速修正、共享主機無權改 ini)
<?php
// 入口檔最開頭(在任何 date/time 函數之前)
date_default_timezone_set('Asia/Taipei');
// 以下代碼...
echo date('Y-m-d H:i:s'); // 正確顯示本地時間
方法三:運行時動態切換(多時區應用)
function getUserTime(string $format, string $userTimezone = 'Asia/Taipei'): string {
$dt = new DateTime('now', new DateTimeZone($userTimezone));
return $dt->format($format);
}
// 或
$dt = new DateTime('now', new DateTimeZone('UTC'));
$dt->setTimezone(new DateTimeZone('Asia/Taipei'));
echo $dt->format('Y-m-d H:i:s');
常見時區識別碼對照
| 地區 | 識別碼 | UTC 偏移 |
| 台灣/香港/北京/新加坡/馬尼拉 | Asia/Taipei / Asia/Hong_Kong / Asia/Shanghai / Asia/Singapore / Asia/Manila | +08:00 |
| 東京/首爾 | Asia/Tokyo / Asia/Seoul | +09:00 |
| 紐約/多倫多 | America/New_York / America/Toronto | -05:00/-04:00 (DST) |
| 倫敦 | Europe/London | +00:00/+01:00 (DST) |
| 悉尼/墨爾本 | Australia/Sydney / Australia/Melbourne | +10:00/+11:00 (DST) |
| UTC 標準時間 | UTC | +00:00 |
完整列表:DateTimeZone::listIdentifiers() 或 PHP 官方文件。
DateTime 類別最佳實踐(PHP 5.2+)
<?php
// 建立時指定時區,避免依賴預設
$dt = new DateTime('2024-01-15 14:30:00', new DateTimeZone('Asia/Taipei'));
// 格式化
echo $dt->format('Y-m-d H:i:s'); // 2024-01-15 14:30:00
// 時區轉換(保留瞬間不變)
$dt->setTimezone(new DateTimeZone('UTC'));
echo $dt->format('Y-m-d H:i:s'); // 2024-01-15 06:30:00
// 運算
$dt->modify('+1 day');
$dt->add(new DateInterval('PT2H30M'));
// 比較
$dt1 = new DateTime('now', new DateTimeZone('Asia/Taipei'));
$dt2 = new DateTime('now', new DateTimeZone('UTC'));
var_dump($dt1 == $dt2); // true(同一瞬間)
常見陷阱與除錯
| 現象 | 原因 | 解決 |
| 系統時間正確但 PHP 錯誤 | PHP 讀取自身時區設定,非系統時間 | 設定 date.timezone |
| DST 夏令時間切換錯誤 | 使用固定偏移(如 Etc/GMT-8)而非具名時區 | 必須用 Asia/Taipei 等具名時區 |
| 資料庫時間不一致 | DB 連線時區、伺服器時區、PHP 時區三者不同 | 統一用 UTC 存儲,顯示時轉換;連線執行 SET time_zone = '+08:00' |
| Docker 容器時間錯誤 | 容器預設 UTC,未掛載 /etc/localtime 或設定 TZ 環境變數 | docker run -e TZ=Asia/Taipei 或 -v /etc/localtime:/etc/localtime:ro |
驗證腳本
<?php
echo 'ini_get: ' . ini_get('date.timezone') . "\n";
echo 'date_default_timezone_get: ' . date_default_timezone_get() . "\n";
echo 'date: ' . date('Y-m-d H:i:s') . "\n";
echo 'DateTime: ' . (new DateTime())->format('Y-m-d H:i:s') . "\n";
echo 'timezone_offset_get: ' . timezone_offset_get(new DateTimeZone('Asia/Taipei'), new DateTime()) . " 秒\n";