兩種 API 風格
| 特性 | 程序式 (date, strtotime...) | 物件導向 (DateTime, DateTimeImmutable) |
| PHP 版本 | 所有版本 | 5.2+ (DateTimeImmutable 5.5+) |
| 時區處理 | 依賴 date_default_timezone_set | 物件內建時區,可各自不同 |
| 不可變性 | N/A | DateTimeImmutable 操作回傳新物件,原物件不變 |
| 型別安全 | 字串/整數 | 強型別,IDE 支援完整 |
| 推薦度 | 簡單快速腳本 | 現代專案標準 |
程序式函數速查
| 函數 | 說明 | 範例 |
date($format, $timestamp?) | 格式化時間戳 | date('Y-m-d H:i:s') → 2024-01-15 14:30:45 |
time() | 目前 Unix 時間戳 (秒) | 1705312245 |
microtime(true) | 含微秒的浮點數時間戳 | 1705312245.1234 |
strtotime($datetime, $base?) | 英文文字解析為時間戳 | strtotime('next Monday') |
mktime($h,$i,$s,$m,$d,$y) | 組合日期時間為時間戳 | mktime(0,0,0,1,1,2024) |
getdate($timestamp?) | 回傳關聯陣列含年月日時分秒 | ['year'=>2024,'mon'=>1,...] |
checkdate($m,$d,$y) | 驗證日期合法性 | checkdate(2,29,2024) → true |
date_default_timezone_set($tz) | 設定預設時區 | date_default_timezone_set('Asia/Taipei') |
DateTime / DateTimeImmutable 核心操作
<?php
// 建立實例
$dt = new DateTime('now', new DateTimeZone('Asia/Taipei'));
$dti = new DateTimeImmutable('2024-01-15 14:30:00', new DateTimeZone('UTC'));
// 格式化輸出
echo $dt->format('Y-m-d H:i:s'); // 2024-01-15 14:30:45
echo $dt->format('c'); // ISO 8601: 2024-01-15T14:30:45+08:00
echo $dt->format('U'); // Unix timestamp
// 修改日期 (DateTime 修改自身, DateTimeImmutable 回傳新物件)
$dt->modify('+1 day'); // $dt 變成隔天
$nextDay = $dti->modify('+1 day'); // $dti 不變, $nextDay 為新物件
// 設定具體值
$dt->setDate(2024, 12, 25);
$dt->setTime(23, 59, 59);
$dt->setTimezone(new DateTimeZone('America/New_York'));
// 運算差值
$diff = $dt1->diff($dt2); // 回傳 DateInterval
echo $diff->format('%a 天 %h 小時 %i 分鐘'); // 間隔天數、時、分
// 加減 DateInterval
$interval = new DateInterval('P1M2D'); // 1個月2天
$dt->add($interval);
$dt->sub($interval);
// 比較
$dt1 > $dt2; // 直接比較物件 (PHP 5.2.2+)
$dt1 == $dt2; // 相同時間點 (含時區換算)
?>
常用格式化字元對照表
| 字元 | 說明 | 範例 |
| Y | 4 位數年份 | 2024 |
| y | 2 位數年份 | 24 |
| m | 月份 (01-12) | 01 |
| n | 月份 (1-12) | 1 |
| F | 月份完整英文名 | January |
| M | 月份縮寫英文 | Jan |
| d | 日期 (01-31) | 15 |
| j | 日期 (1-31) | 15 |
| l | 星期完整英文名 | Monday |
| D | 星期縮寫英文 | Mon |
| N | ISO-8601 星期數 (1=Mon..7=Sun) | 1 |
| w | 星期數 (0=Sun..6=Sat) | 1 |
| H | 24 小時制 (00-23) | 14 |
| h | 12 小時制 (01-12) | 02 |
| i | 分鐘 (00-59) | 30 |
| s | 秒 (00-59) | 45 |
| u | 微秒 (000000-999999) | 123456 |
| A | AM/PM 大寫 | PM |
| a | am/pm 小寫 | pm |
| O | 時差 +0800 | +0800 |
| P | 時差 +08:00 | +08:00 |
| c | ISO 8601 完整格式 | 2024-01-15T14:30:45+08:00 |
| r | RFC 2822 格式 | Mon, 15 Jan 2024 14:30:45 +0800 |
實戰工具函數庫
<?php
declare(strict_types=1);
class DateHelper
{
/** 取得指定月份的第一天與最後一天 */
public static function monthRange(int $year, int $month): array {
$first = new DateTimeImmutable("{$year}-{$month}-01");
$last = $first->modify('last day of this month');
return ['first' => $first, 'last' => $last];
}
/** 判斷是否為週末 */
public static function isWeekend(DateTimeInterface $date): bool {
$day = (int)$date->format('N');
return $day >= 6;
}
/** 計算年齡 (滿歲) */
public static function calculateAge(DateTimeInterface $birth, ?DateTimeInterface $reference = null): int {
$ref = $reference ?? new DateTimeImmutable('now', $birth->getTimezone());
$diff = $birth->diff($ref);
return $diff->y;
}
/** 產生日期區間迭代器 (Generator) */
public static function dateRange(DateTimeInterface $start, DateTimeInterface $end, string $intervalSpec = 'P1D'): Generator {
$interval = new DateInterval($intervalSpec);
$current = clone $start;
$end = clone $end;
$end->modify('+1 day'); // 包含結束日
while ($current < $end) {
yield $current;
$current->add($interval);
}
}
/** 格式化為中文友善顯示 */
public static function formatChinese(DateTimeInterface $dt, bool $showTime = true): string {
$fmt = $showTime ? 'Y年n月j日 H:i' : 'Y年n月j日';
return $dt->format($fmt);
}
}
// 使用範例
foreach (DateHelper::dateRange(new DateTime('2024-01-01'), new DateTime('2024-01-05')) as $day) {
echo DateHelper::formatChinese($day, false) . ($day->format('N') >= 6 ? ' (週末)' : '') . "\n";
}
?>
時區資料庫與最佳實踐
- 系統層級:
php.ini 設定 date.timezone = "Asia/Taipei",避免每次腳本啟動猜測。
- 資料庫層級:MySQL 使用
TIMESTAMP (自動 UTC 轉換) 或 DATETIME (存原始) + 應用層統一 UTC 存儲,顯示時轉換使用者時區。
- 前端交互:API 傳輸統一 ISO 8601 UTC (
2024-01-15T06:30:45Z),前端用 Intl.DateTimeFormat 或 date-fns-tz 顯示本地時間。
- 定時任務:Cron 設定系統時區或腳本內
date_default_timezone_set,避免夏令時間切換導致執行時間偏移。
結語
現代 PHP 專案應以 DateTimeImmutable 為核心,搭配 DateInterval、DatePeriod、DateTimeZone 組成完整的日期時間處理體系。程序式函數保留給極簡單的單次格式化需求,複雜業務邏輯請毫不猶豫選用物件導向 API。