DateTime 是 PHP 5.2+ 核心擴展提供的面向對象日期時間處理類,比傳統 date()/strtotime() 更強大、鏈式調用更優雅、時區處理更安全。本文梳理 15 個高頻使用場景。
在命名空間中使用原生類需加前導反斜杠:new \DateTime();全局命名空間可直接 new DateTime()。
$dt = new \DateTime();
echo $dt->format('Y-m-d H:i:s'); // 2024-01-15 14:30:45
$dt = new \DateTime('2024-12-25');
echo $dt->format('Y-m-d'); // 2024-12-25
$dt = \DateTime::createFromFormat('Ymd', '20241225');
echo $dt->format('Y-m-d'); // 2024-12-25
// 獲取時間戳(PHP 5.3+ 推薦)
$dt = new \DateTime();
$timestamp = $dt->getTimestamp(); // 1705312245
// 時間戳轉 DateTime
$dt = new \DateTime();
$dt->setTimestamp(1705312245);
echo $dt->format('Y-m-d H:i:s');
⚠️format('U')在 32 位系統 1901 年前會返回負數,getTimestamp()返回 false,推薦統一用getTimestamp()/setTimestamp()。
$dt1 = new \DateTime('2024-01-01 10:00:00');
$dt2 = new \DateTime('2025-06-15 22:30:00');
$diff = $dt1->diff($dt2); // 返回 DateInterval
echo $diff->format('%Y年 %m月 %d天 %h小時 %i分鐘 %s秒');
// 輸出:1年 5月 14天 12小時 30分鐘 0秒
%R 可顯示正負號(+/-),%a 總天數差。
$dt = new \DateTime();
$interval = new \DateInterval('P2DT5H'); // 2天5小時
// 或:$interval = \DateInterval::createFromDateString('1 month');
$dt->add($interval);
echo $dt->format('Y-m-d H:i:s');
間隔規範:P開頭,Y/M/D/W/H/M/S 分別代表年月日周時分秒,時間部分前加 T。
$dt = new \DateTime();
$dt->sub(new \DateInterval('P2DT5H'));
echo $dt->format('Y-m-d H:i:s');
$dt = new \DateTime('2024-12-31');
$dt->modify('-1 month');
echo $dt->format('Y-m-d'); // 2024-11-30(非單純減 30 天)
modify() 支援 +1 day、next Monday、last day of next month 等自然語言。
$dt = new \DateTime();
$dt->setDate(2025, 2, 28);
echo $dt->format('Y-m-d'); // 2025-02-28
$dt = new \DateTime();
$dt->setTime(23, 59, 59);
echo $dt->format('H:i:s'); // 23:59:59
$dt = new \DateTime('now', new \DateTimeZone('Asia/Shanghai'));
// 或
$dt->setTimezone(new \DateTimeZone('America/New_York'));
echo $dt->format('Y-m-d H:i:s T'); // 2024-01-15 01:30:45 EST
$dt = new \DateTime(null, new \DateTimeZone('Asia/Shanghai'));
$tz = $dt->getTimezone();
echo $tz->getName(); // Asia/Shanghai
$tzTaipei = new \DateTimeZone('Asia/Taipei');
$tzTokyo = new \DateTimeZone('Asia/Tokyo');
$dtTaipei = new \DateTime('now', $tzTaipei);
$dtTokyo = new \DateTime('now', $tzTokyo);
// getOffset 參數需傳入一個 DateTime 以確定是否夏令時
$offset = $tzTokyo->getOffset($dtTaipei); // 秒數
echo $offset / 3600; // 1 (東京比台北快 1 小時)
$interval = new \DateInterval('P2Y4DT6H8M');
echo $interval->format('%y年 %d天 %h小時 %i分鐘'); // 2年 4天 6小時 8分鐘
$start = new \DateTime('2024-01-01');
$interval = \DateInterval::createFromDateString('1 day');
$period = new \DatePeriod($start, $interval, 10); // 10 次迭代
foreach ($period as $date) {
echo $date->format('Y-m-d') . "\n";
}
// 輸出 2024-01-01 到 2024-01-10
排除開始日期:new \DatePeriod($start, $interval, 10, \DatePeriod::EXCLUDE_START_DATE)
| 場景 | 推薦方法 | 避坑提示 |
|---|---|---|
| 用戶生日存儲 | setDate() + MySQL DATE 類型 | 勿用字符串存儲 |
| 定時任務判斷 | modify('+1 day') + format('H:i') | 注意夏令時邊界 |
| API 返回時間 | format('c') (ISO 8601) / format('U') (時間戳) | 統一 UTC 存儲,前端轉換 |
| 跨時區會議 | setTimezone() 轉換展示 | 數據庫存 UTC |
| 計算年齡 | diff()->y | 比 (time()-birth)/31536000 精確 |
DateTime + DateInterval + DatePeriod + DateTimeZone 組成 PHP 日期時間處理的「四大金剛」。建議項目中封裝 DateHelper 靜態類統一入口,內部委託給 DateTime,對外提供 now()、parse()、diffForHumans() 等語義化方法,屏蔽底層細節,提升團隊開發效率。