計算年齡看似簡單,實則涉及閏年、月日比較等邊界情況。本文提供兩種健壯的 PHP 實現:時間戳法與日期拆分法,均正確處理「生日是否已過」邏輯。
function getAge(string $birthday): int|false {
$ts = strtotime($birthday);
if ($ts === false) return false; // 格式無效
[$y1, $m1, $d1] = explode('-', date('Y-m-d', $ts));
[$y2, $m2, $d2] = explode('-', date('Y-m-d'));
$age = $y2 - $y1;
// 如果今年的生日還沒到,年齡 -1
if (($m2 . $d2) < ($m1 . $d1)) $age--;
return $age;
}
// 測試
echo getAge('1990-05-15'); // 假設今天 2024-03-10 → 33
echo getAge('2010-02-29'); // 閏年出生,非閏年按 2/28 或 3/1 算,邏輯自動處理
function getAgeSimple(string $birthday): int {
[$by, $bm, $bd] = explode('-', $birthday);
$cy = (int)date('Y');
$cm = (int)date('m');
$cd = (int)date('d');
$age = $cy - $by;
if ($cm < $bm || ($cm == $bm && $cd < $bd)) $age--;
return $age;
}
function getAgeOOP(string $birthday): int {
$birth = new DateTime($birthday);
$today = new DateTime('today');
$diff = $birth->diff($today);
return $diff->y; // DateInterval 的 y 屬性已自動處理生日是否已過
}
// 使用
echo getAgeOOP('1995-12-25');
| 出生日期 | 今天 | 預期年齡 | 說明 |
|---|---|---|---|
| 2000-01-01 | 2024-01-01 | 24 | 生日剛好今天 |
| 2000-01-01 | 2023-12-31 | 23 | 生日尚未到 |
| 2012-02-29 | 2024-02-28 | 11 | 閏年出生,非閏年 2/28 視為生日已過 |
| 2012-02-29 | 2024-03-01 | 12 | 閏年,生日 2/29 已過 |
| invalid | -- | false | 格式錯誤返回 false |
date('Y') - date('Y', strtotime($birthday)):忽略月日,會導致生日未到時年齡偏大 1 歲。floor((time() - strtotime($birthday)) / 31536000):忽略閏年、月長差異,誤差累積。DateTime::diff():內部已正確處理日曆邏輯,代碼最簡潔、可維護性最強。$birth = new DateTime('1990-05-15');
$today = new DateTime('today');
// 虛歲:出生即 1 歲,每過一年 +1
$xusui = $today->diff($birth)->y + 1;
// 下次生日
$nextBirthday = clone $birth;
$nextBirthday->setDate((int)$today->format('Y'), (int)$birth->format('m'), (int)$birth->format('d'));
if ($nextBirthday <= $today) $nextBirthday->modify('+1 year');
$daysLeft = $today->diff($nextBirthday)->days;
echo "周歲: {$today->diff($birth)->y}, 虛歲: $xusui, 距離下次生日: $daysLeft 天";
推薦在項目中統一使用 DateTime 系列類,避免手動拼接字符串比較帶來的隱患。