一、date() 格式化字元速查表 (已在 148406 詳細列出,此處補充進階)
ISO 8601 / RFC 標準格式
| 字元 | 標準 | 範例 |
c | ISO 8601 | 2024-01-15T14:30:00+08:00 |
r | RFC 2822 | Mon, 15 Jan 2024 14:30:00 +0800 |
U | Unix 時間戳 | 1705300200 |
二、時區設定:解決「差 8 小時」的三種方式
<?php
// 1. php.ini (永久、全域)
; date.timezone = "Asia/Taipei"
// 2. 程式碼啟動時 (共享主機常用)
date_default_timezone_set('Asia/Taipei'); // 或 PRC, Asia/Shanghai, Asia/Hong_Kong
// 3. 運行時單次覆蓋
ini_set('date.timezone', 'Asia/Taipei');
// 驗證
echo date('Y-m-d H:i:s e'); // 2024-01-15 14:30:00 Asia/Taipei
?>
三、本地化輸出:從 setlocale+strftime 到 IntlDateFormatter
⚠️ 重要遷移提醒
strftime() / gmstrftime() **自 PHP 8.1 起棄用**,PHP 9.0 將移除。新專案**請直接使用 IntlDateFormatter** (需安裝 intl 擴展,現代 PHP 環境預設內建)。
舊式 setlocale + strftime (僅供維護舊專案參考)
<?php
// 設定地區 (Linux 系統需安裝對應 locale 套件)
setlocale(LC_TIME, 'zh_TW.utf8', 'zh_CN.utf8', 'en_US.utf8');
echo strftime('%Y年%m月%d日 %A %H:%M:%S', time());
// 輸出:2024年01月15日 星期一 14:30:00 (視系統 locale 支援度而定)
?>
現代標準:IntlDateFormatter (ICU 庫、跨平台一致、支援 600+ 地區)
<?php
// 基本用法
$fmt = new IntlDateFormatter(
'zh_TW', // 地區代碼 (繁體中文台灣)
IntlDateFormatter::FULL, // 日期風格: FULL/LONG/MEDIUM/SHORT
IntlDateFormatter::FULL, // 時間風格
'Asia/Taipei', // 時區
IntlDateFormatter::GREGORIAN // 曆法
);
echo $fmt->format(time());
// 2024年1月15日 星期一 下午02時30分05秒 台灣標準時間
// 自訂格式模式 (ICU 格式語法)
$fmt->setPattern('yyyy年MM月dd日 EEEE');
echo $fmt->format(time()); // 2024年01月15日 星期一
$fmt->setPattern('yyyy-MM-dd HH:mm:ss z');
echo $fmt->format(time()); // 2024-01-15 14:30:05 台灣標準時間
// 相對時間格式化 (PHP 7.3+ NumberFormatter::formatRelative)
$relFmt = new IntlDateFormatter(
'zh_TW',
IntlDateFormatter::NONE,
IntlDateFormatter::SHORT,
'Asia/Taipei'
);
// 需搭配 RelativeDateTimeFormatter (PHP 8.0+) 或手動計算差值
?>
常用 ICU 模式字元對照
| 模式 | 意義 | 範例 |
yyyy | 4 位年份 | 2024 |
yy | 2 位年份 | 24 |
MM | 月份 01-12 | 01 |
MMM | 月份縮寫 | 1月 |
MMMM | 月份全名 | 一月 |
dd | 日期 01-31 | 15 |
EEEE | 星期全名 | 星期一 |
E | 星期縮寫 | 週一 |
HH | 24制小時 00-23 | 14 |
hh | 12制小時 01-12 | 02 |
mm | 分鐘 00-59 | 30 |
ss | 秒 00-59 | 05 |
a | AM/PM | 下午 |
z | 時區名稱 | 台灣標準時間 |
Z | 時區偏移 | +0800 |
四、DateTime + IntlDateFormatter 現代化最佳組合
<?php
// 建立時區感知的 DateTime 物件
$dt = new DateTime('2024-01-15 14:30:00', new DateTimeZone('UTC'));
// 轉換至目標時區
$dt->setTimezone(new DateTimeZone('Asia/Taipei'));
// 格式化輸出
$fmt = new IntlDateFormatter('zh_TW', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'Asia/Taipei');
echo $fmt->format($dt); // 2024/01/15 下午 02:30
// 相對時間 (人類可讀)
function formatRelative(DateTime $dt, string $locale = 'zh_TW'): string {
$now = new DateTime('now', $dt->getTimezone());
$diff = $now->getTimestamp() - $dt->getTimestamp();
$units = [
31536000 => '年',
2592000 => '月',
86400 => '天',
3600 => '小時',
60 => '分鐘',
1 => '秒',
];
foreach ($units as $sec => $unit) {
if ($diff >= $sec) {
$val = intdiv($diff, $sec);
return "{$val}{$unit}前";
}
}
return '剛剛';
}
echo formatRelative(new DateTime('-2 hours')); // 2小時前
?>
五、常見格式化需求一鍷複製
<?php
$now = new DateTime('now', new DateTimeZone('Asia/Taipei'));
// 資料庫儲存標準
$dbFormat = $now->format('Y-m-d H:i:s'); // 2024-01-15 14:30:00
// API 回傳標準 (ISO 8601)
$apiFormat = $now->format('c'); // 2024-01-15T14:30:00+08:00
// 日誌檔名
$logFile = $now->format('Y-m-d_H-i-s'); // 2024-01-15_14-30-00
// 使用者顯示 (繁中)
$fmt = new IntlDateFormatter('zh_TW', IntlDateFormatter::LONG, IntlDateFormatter::SHORT, 'Asia/Taipei');
$userFormat = $fmt->format($now); // 2024年1月15日 下午 02:30
// 相對時間
echo formatRelative($now->modify('-3 days')); // 3天前
?>
六、效能微調建議
date() 最快 (C 級函式),單純格式化首選。
DateTime::format() 略慢但支援時區物件操作。
IntlDateFormatter 較重 (ICU 庫),**建議實例化一次重複使用**,避免迴圈中 new。
- 高頻呼叫 (如日誌每行) 可用
gmdate() + 手動時區偏移字串拼接。