PHP 處理日期時間是開發高頻需求。本文系統整理 strtotime()、DateTime 類別、格式化輸出、運算技巧與常見坑點,並提供可直接複製的程式碼片段。
<?php
// PHP 5.1+ 必須設定預設時區,避免警告
date_default_timezone_set('Asia/Taipei'); // 或 UTC, America/Los_Angeles 等
$now = time(); // 當前 Unix timestamp
echo "現在時間戳: $now\n";
echo "date() 格式化: " . date('Y-m-d H:i:s', $now) . "\n";
echo "strftime() 格式化: " . strftime('%Y-%m-%d %H:%M:%S', $now) . "\n";
strtotime() 能解析英文文字日期描述,支援相對時間運算,是日期計算首選工具。
$base = '2024-01-15 12:00:00'; // 基準時間
echo "3 天後: " . date('Y-m-d', strtotime('+3 days', strtotime($base))) . "\n"; // 2024-01-18
echo "3 天前: " . date('Y-m-d', strtotime('-3 days', strtotime($base))) . "\n"; // 2024-01-12
echo "1 個月後: " . date('Y-m-d', strtotime('+1 month', strtotime($base))) . "\n"; // 2024-02-15
echo "2 個月前: " . date('Y-m-d', strtotime('-2 months', strtotime($base))) . "\n"; // 2023-11-15
echo "1 年後: " . date('Y-m-d', strtotime('+1 year', strtotime($base))) . "\n"; // 2025-01-15
echo "2 小時前: " . date('H:i:s', strtotime('-2 hours', strtotime($base))) . "\n"; // 10:00:00
echo "下週一: " . date('Y-m-d', strtotime('next Monday', strtotime($base))) . "\n";
echo "本月最後一天: " . date('Y-m-d', strtotime('last day of this month', strtotime($base))) . "\n";
echo "下月第一天: " . date('Y-m-d', strtotime('first day of next month', strtotime($base))) . "\n";
// 32 位元 PHP strtotime 不支援 1901-12-13 以前;64 位元 PHP 7/8 已解決
$dt = new DateTime('1929-02-10');
echo "DateTime 1929: " . $dt->format('Y-m-d') . "\n"; // 正常輸出
// 或用 DateTime::createFromFormat 解析任意格式
$dt = DateTime::createFromFormat('Y-m-d', '1929-02-10');
echo "createFromFormat: " . $dt->format('Y-m-d') . "\n";
DateTime 不受 32 位元限制,支援鏈式操作、時區轉換、差值計算,現代 PHP 首選。
$dt = new DateTime('2024-01-15 12:26:36', new DateTimeZone('Asia/Taipei'));
echo "原始: " . $dt->format('Y-m-d H:i:s') . "\n";
// 修改日期/時間
$dt->setDate(2024, 2, 28);
echo "改日期: " . $dt->format('Y-m-d H:i:s') . "\n"; // 2024-02-28 12:26:36
$dt->setTime(18, 30, 0);
echo "改時間: " . $dt->format('Y-m-d H:i:s') . "\n"; // 2024-02-28 18:30:00
// 相對運算(modify 回傳 $this 可鏈式)
$dt->modify('+7 hours');
echo "+7小時: " . $dt->format('Y-m-d H:i:s') . "\n"; // 2024-02-29 01:30:00
$dt->modify('3 days');
echo "+3天: " . $dt->format('Y-m-d H:i:s') . "\n"; // 2024-03-03 01:30:00
$dt->modify('-1 month');
echo "-1月: " . $dt->format('Y-m-d H:i:s') . "\n"; // 2024-02-03 01:30:00
$dt->modify('last day of this month');
echo "本月最後一天: " . $dt->format('Y-m-d') . "\n";
$start = new DateTime('2024-01-01');
$end = new DateTime('2024-01-15');
$diff = $start->diff($end);
echo "相差天數: " . $diff->days . "\n"; // 14
echo "相差月數: " . ($diff->m + $diff->y * 12) . "\n"; // 0
echo "完整差值: " . $diff->format('%a 天 %h 小時 %i 分') . "\n";
$dt = new DateTime('2024-01-15 12:00:00', new DateTimeZone('Asia/Taipei'));
echo "台北: " . $dt->format('Y-m-d H:i:s T') . "\n";
$dt->setTimezone(new DateTimeZone('UTC'));
echo "UTC: " . $dt->format('Y-m-d H:i:s T') . "\n";
$dt->setTimezone(new DateTimeZone('America/New_York'));
echo "紐約: " . $dt->format('Y-m-d H:i:s T') . "\n";
| 字元 | 說明 | 範例 |
|---|---|---|
| Y | 4 位數年份 | 2024 |
| y | 2 位數年份 | 24 |
| m | 月份(01-12) | 01 |
| n | 月份(1-12) | 1 |
| d | 日期(01-31) | 15 |
| j | 日期(1-31) | 15 |
| H | 24小時制(00-23) | 14 |
| h | 12小時制(01-12) | 02 |
| i | 分鐘(00-59) | 30 |
| s | 秒數(00-59) | 45 |
| w | 星期(0=星期日) | 1 |
| t | 當月總天數 | 31 |
| L | 是否閏年(1/0) | 1 |
<?php
/**
* 取得指定年月的天數
*/
function daysInMonth(int $year, int $month): int
{
return (int)date('t', mktime(0, 0, 0, $month, 1, $year));
}
/**
* 判斷日期是否有效
*/
function isValidDate(int $year, int $month, int $day): bool
{
return checkdate($month, $day, $year);
}
/**
* 取得兩日期相差天數(含起迄日)
*/
function diffDays(string $date1, string $date2): int
{
$d1 = new DateTime($date1);
$d2 = new DateTime($date2);
return abs($d1->diff($d2)->days);
}
/**
* 取得 N 個工作日後的日期(排除週六日)
*/
function addWorkDays(string $date, int $days): string
{
$dt = new DateTime($date);
$added = 0;
while ($added < $days) {
$dt->modify('+1 day');
if ($dt->format('N') < 6) { // 1-5 週一至週五
$added++;
}
}
return $dt->format('Y-m-d');
}
/**
* 格式化為中文日期
*/
function formatChineseDate(string $date): string
{
$dt = new DateTime($date);
$week = ['日','一','二','三','四','五','六'];
return $dt->format('Y年m月d日') . ' 星期' . $week[$dt->format('w')];
}
// 使用範例
echo "2024-02 天數: " . daysInMonth(2024, 2) . "\n"; // 29
echo "是否有效: " . (isValidDate(2024, 2, 29) ? '是' : '否') . "\n";
echo "相差天數: " . diffDays('2024-01-01', '2024-01-15') . "\n"; // 14
echo "5工作日後: " . addWorkDays('2024-01-10', 5) . "\n";
echo "中文格式: " . formatChineseDate('2024-01-15') . "\n";
'first day of -1 month' 或 'last day of -1 month' 明確控制。date('Y-m-d', -800) 在 32 位元系統回傳 1970-01-01,請改用 DateTime。strftime() 在 PHP 8.1+ 棄用,建議全面改用 DateTime::format() 或 IntlDateFormatter。TIMESTAMP 或 DATETIME,應用層統一用 UTC,顯示時再轉使用者時區。現代 PHP 日期時間運算首選 DateTime 類別,功能完整、無 32 位元限制、支援鏈式操作。strtotime() 適合簡單相對運算與字串解析。掌握時區處理、差值計算與格式化,即能應付絕大多數業務場景。