PHP 日期與時間 (Date & Time)

PHP 提供多種方式處理日期和時間。傳統方式使用 date()time() 等函數,現代方式則推薦使用 DateTime 類別,後者提供更強大且物件導向的操作方式。

基本函數

date()

<?php
// 目前日期時間
echo date('Y-m-d');        // 2024-12-09
echo date('H:i:s');        // 14:30:00
echo date('Y-m-d H:i:s');  // 2024-12-09 14:30:00

// 常用格式化字元
// Y - 四位數年份
// m - 月份(01-12)
// d - 日期(01-31)
// H - 小時(00-23)
// i - 分鐘(00-59)
// s - 秒(00-59)
// l - 星期幾(Sunday-Saturday)
// F - 月份名稱(January-December)
?>

time() 和 mktime()

<?php
// 目前時間戳記
$now = time();
echo $now;  // 1702108200

// 建立特定時間戳記
$timestamp = mktime(14, 30, 0, 12, 9, 2024);
echo date('Y-m-d H:i:s', $timestamp);

// 從字串解析
$timestamp = strtotime('2024-12-09');
$timestamp = strtotime('next Monday');
$timestamp = strtotime('+1 week');
?>

DateTime 類別

<?php
// 建立 DateTime
$date = new DateTime();  // 現在
$date = new DateTime('2024-12-09');
$date = new DateTime('2024-12-09 14:30:00');

// 格式化輸出
echo $date->format('Y-m-d');        // 2024-12-09
echo $date->format('Y年m月d日');    // 2024年12月09日

// 從格式建立
$date = DateTime::createFromFormat('d/m/Y', '09/12/2024');
?>

時區

<?php
// 設定預設時區
date_default_timezone_set('Asia/Taipei');

// DateTime 使用時區
$date = new DateTime('now', new DateTimeZone('Asia/Taipei'));
echo $date->format('Y-m-d H:i:s');

// 轉換時區
$date = new DateTime('2024-12-09 14:00:00', new DateTimeZone('UTC'));
$date->setTimezone(new DateTimeZone('Asia/Taipei'));
echo $date->format('Y-m-d H:i:s');  // 2024-12-09 22:00:00
?>

日期運算

DateInterval

DateInterval 用於表示一段時間間隔。建構子接受一個符合 ISO 8601 格式的字串:P 開頭表示 Period,後接數字和單位(Y 年、M 月、D 日);T 分隔時間部分(H 時、M 分、S 秒)。

<?php
$date = new DateTime('2024-12-09');

// 加時間
$date->add(new DateInterval('P1D'));     // +1 天
$date->add(new DateInterval('P1M'));     // +1 個月
$date->add(new DateInterval('P1Y'));     // +1 年
$date->add(new DateInterval('PT1H'));    // +1 小時
$date->add(new DateInterval('P1DT2H'));  // +1 天 2 小時

// 減時間
$date->sub(new DateInterval('P1D'));

// 使用 modify
$date->modify('+1 day');
$date->modify('-1 week');
$date->modify('next Monday');
?>

計算差異

<?php
$date1 = new DateTime('2024-01-01');
$date2 = new DateTime('2024-12-31');

$diff = $date1->diff($date2);

echo $diff->days;   // 365(總天數)
echo $diff->y;      // 0(年)
echo $diff->m;      // 11(月)
echo $diff->d;      // 30(日)

// 格式化差異
echo $diff->format('%y 年 %m 個月 %d 天');
?>

DatePeriod

DatePeriod 可以產生一段期間內的日期序列,常用於需要遍歷日期的場景(如行事曆、報表):

<?php
$start = new DateTime('2024-01-01');
$end = new DateTime('2024-01-10');
$interval = new DateInterval('P1D');

$period = new DatePeriod($start, $interval, $end);

foreach ($period as $date) {
    echo $date->format('Y-m-d') . "\n";
}
// 2024-01-01
// 2024-01-02
// ...
// 2024-01-09
?>

日期比較

<?php
$date1 = new DateTime('2024-01-01');
$date2 = new DateTime('2024-12-31');

if ($date1 < $date2) {
    echo "date1 較早";
}

if ($date1 == $date2) {
    echo "相同";
}

// 檢查是否在範圍內
$now = new DateTime();
$start = new DateTime('2024-01-01');
$end = new DateTime('2024-12-31');

if ($now >= $start && $now <= $end) {
    echo "在範圍內";
}
?>

不可變 DateTime

DateTimeImmutableDateTime 用法相同,但操作後會回傳新物件而非修改原物件。這在需要保留原始日期或避免意外修改時特別有用:

<?php
// DateTimeImmutable 不會改變原物件
$date = new DateTimeImmutable('2024-12-09');
$newDate = $date->add(new DateInterval('P1D'));

echo $date->format('Y-m-d');     // 2024-12-09(不變)
echo $newDate->format('Y-m-d');  // 2024-12-10
?>

實際應用

<?php
// 計算年齡
function calculateAge(string $birthday): int {
    $birth = new DateTime($birthday);
    $now = new DateTime();
    return $now->diff($birth)->y;
}

echo calculateAge('1990-05-15');  // 34

// 格式化相對時間
function timeAgo(DateTime $date): string {
    $now = new DateTime();
    $diff = $now->diff($date);
    
    if ($diff->y > 0) return $diff->y . ' 年前';
    if ($diff->m > 0) return $diff->m . ' 個月前';
    if ($diff->d > 0) return $diff->d . ' 天前';
    if ($diff->h > 0) return $diff->h . ' 小時前';
    if ($diff->i > 0) return $diff->i . ' 分鐘前';
    return '剛剛';
}
?>