<?php
$now = time();
// 30 天后
echo date('Y-m-d', strtotime('+30 days', $now));
// 3 月前
echo date('Y-m-d', strtotime('-3 months', $now));
// 1 年後
echo date('Y-m-d', strtotime('+1 year', $now));
// 具體組合
echo date('Y-m-d H:i:s', strtotime('+1 week 2 days 3 hours', $now));
// 本月第一天 00:00:00
echo date('Y-m-01 00:00:00');
// 本月最後一天 23:59:59
echo date('Y-m-t 23:59:59');
?>
<?php
function diffHuman(string $start, string $end): array {
$s = strtotime($start);
$e = strtotime($end);
$diff = abs($e - $s); // 秒數差
return [
'days' => floor($diff / 86400),
'hours' => floor(($diff % 86400) / 3600),
'minutes' => floor(($diff % 3600) / 60),
'seconds' => $diff % 60,
'total_seconds' => $diff,
];
}
print_r(diffHuman('2024-01-01', '2024-05-13 15:30:00'));
// Array ( [days]=>133 [hours]=>15 [minutes]=>30 [seconds]=>0 [total_seconds]=>11486100 )
?>
<?php
function isThisWeek(string $date): bool {
// date('W') 返回 ISO-8601 年份周號 (需同年份)
return date('oW', strtotime($date)) === date('oW');
}
// 測試
var_dump(isThisWeek('2024-05-10')); // 視當前日期而定
?>
<?php
// ❌ 錯誤:固定 90 天
$wrong = date('Y-m-d', strtotime('-90 days'));
// ✅ 正確:月份運算自動處理月末邊界
$correct = date('Y-m-d', strtotime('-3 months'));
// 2024-05-13 -> 2024-02-13 (自動處理 2 月 29 天)
?>
面向對象、不可變、時區感知、鏈式調用、支援 > 2038 年。
<?php
// 創建
$dt = new DateTime('now', new DateTimeZone('Asia/Taipei'));
$dt = DateTime::createFromFormat('Y-m-d H:i:s', '2024-05-13 15:30:00', new DateTimeZone('UTC'));
// 格式化輸出
echo $dt->format('Y-m-d H:i:s'); // 2024-05-13 15:30:00
echo $dt->format('c'); // ISO 8601: 2024-05-13T15:30:00+08:00
// 修改 (可變對象)
$dt->modify('+1 month');
$dt->modify('last day of this month');
$dt->setTime(23, 59, 59);
// 不可變對象 (推薦,避免副作用)
$immutable = new DateTimeImmutable('now');
$nextWeek = $immutable->modify('+1 week'); // 返回新對象,$immutable 不變
// 差值計算
$start = new DateTime('2024-01-01');
$end = new DateTime('2024-05-13');
$interval = $start->diff($end);
echo $interval->format('%a 天 %h 小時 %i 分鐘'); // 133 天 0 小時 0 分鐘
echo $interval->days; // 總天數 133
echo $interval->invert; // 1 表示 start > end
// 時區轉換
$utc = new DateTime('2024-05-13 07:30:00', new DateTimeZone('UTC'));
$utc->setTimezone(new DateTimeZone('Asia/Taipei'));
echo $utc->format('Y-m-d H:i:s'); // 2024-05-13 15:30:00
// 比較
$dt1 = new DateTime('2024-05-13');
$dt2 = new DateTime('2024-05-14');
var_dump($dt1 < $dt2); // bool(true) - 直接支援比較運算符
?>
<?php
class DateHelper {
// 獲取指定日期所在週的開始(週一)與結束(週日)
public static function weekRange(string $date = 'now'): array {
$dt = new DateTime($date);
$dt->modify('monday this week');
$start = clone $dt;
$end = clone $dt;
$end->modify('sunday this week')->setTime(23, 59, 59);
return ['start' => $start, 'end' => $end];
}
// 獲取指定月份範圍
public static function monthRange(string $date = 'now'): array {
$dt = new DateTime($date);
$start = clone $dt;
$start->modify('first day of this month')->setTime(0, 0, 0);
$end = clone $dt;
$end->modify('last day of this month')->setTime(23, 59, 59);
return ['start' => $start, 'end' => $end];
}
// 年齡計算
public static function age(string $birthdate): int {
$birth = new DateTime($birthdate);
$today = new DateTime('today');
return $today->diff($birth)->y;
}
// 友好時間顯示 (幾秒前、幾分鐘前、昨天、具體日期)
public static function humanDiff(string $datetime): string {
$dt = new DateTime($datetime);
$now = new DateTime('now');
$diff = $now->getTimestamp() - $dt->getTimestamp();
if ($diff < 60) return "{$diff}秒前";
if ($diff < 3600) return floor($diff/60) . "分鐘前";
if ($diff < 86400) return floor($diff/3600) . "小時前";
if ($diff < 172800) return "昨天 " . $dt->format('H:i');
if ($diff < 604800) return floor($diff/86400) . "天前";
return $dt->format('Y-m-d');
}
// 判斷是否為工作日 (簡易版,不含節假日)
public static function isWeekday(string $date = 'now'): bool {
$dt = new DateTime($date);
$w = (int)$dt->format('N'); // 1-7 (週一到週日)
return $w >= 1 && $w <= 5;
}
}
?>
| 坑點 | 錯誤示例 | 正確做法 |
|---|---|---|
| 時區未設置 | 直接用 date() 報 Warning | php.ini 設 date.timezone 或 date_default_timezone_set() |
| strtotime 歧義格式 | '05/06/2024' 美/歐制不同 | 用 DateTime::createFromFormat() 指定格式 |
| 月份加減邊界 | 1月31日 +1月 = 3月3日 | 用 modify('first day of +1 month') 或 last day of |
| 夏令時切換 | 時間差計算出現 23/25 小時天 | 用 DateTime diff() 自動處理,或統一用 UTC 存儲計算 |
| 可變對象副作用 | $dt->modify() 影響原變量 | 用 DateTimeImmutable 或 clone |
| 32位系統 2038 年 | time() 返回負數 | 升級 64位 PHP 或全面使用 DateTime |
DateTimeImmutable:類型安全、不可變、鏈式、時區正確。DATETIME 或 TIMESTAMP 均存 UTC,展示層按用戶時區轉換。strtotime/date 調用。nesbot/carbon (Laravel 內建) 或 brick/date-time,功能更豐富。掌握 DateTime 體系,告別時間戳字符串拼接的混亂時代,編寫經得起時區、夏令時、閏年、2038 年考驗的時間代碼。