所有計算的基礎是 time() 或 strtotime() 取得的 UTC 秒數。兩時間戳相減得「秒差」,再換算各單位。
define('SECOND', 1);
define('MINUTE', 60);
define('HOUR', 3600);
define('DAY', 86400);
define('MONTH', 2592000); // 30 天近似
define('YEAR', 31536000); // 365 天近似
<?php
/**
* 計算兩個時間的精確差值
* @param int|string $start 開始時間 (時間戳或可解析字串)
* @param int|string $end 結束時間
* @return array ['days'=>, 'hours'=>, 'minutes'=>, 'seconds'=>, 'total_seconds'=>]
*/
function diffTime($start, $end): array {
$startTs = is_numeric($start) ? (int)$start : strtotime($start);
$endTs = is_numeric($end) ? (int)$end : strtotime($end);
if ($startTs > $endTs) { [$startTs, $endTs] = [$endTs, $startTs]; }
$diff = $endTs - $startTs;
$days = intdiv($diff, DAY);
$hours = intdiv($diff % DAY, HOUR);
$minutes = intdiv($diff % HOUR, MINUTE);
$seconds = $diff % MINUTE;
return compact('days', 'hours', 'minutes', 'seconds', 'diff');
}
// 使用
$r = diffTime('2010-12-11 11:40:00', '2012-12-12 11:45:09');
echo "{$r['days']}天 {$r['hours']}小時 {$r['minutes']}分 {$r['seconds']}秒";
// 輸出:731天 0小時 5分 9秒
<?php
/**
* 計算月份差(以「年月」為單位,忽略日)
* 例:2011-05 ~ 2012-12 = 20 個月
*/
function diffMonths($start, $end): int {
$startTs = is_numeric($start) ? (int)$start : strtotime($start);
$endTs = is_numeric($end) ? (int)$end : strtotime($end);
if ($startTs > $endTs) { [$startTs, $endTs] = [$endTs, $startTs]; }
$sy = (int)date('Y', $startTs);
$sm = (int)date('n', $startTs);
$ey = (int)date('Y', $endTs);
$em = (int)date('n', $endTs);
return ($ey - $sy) * 12 + ($em - $sm);
}
// 另一種寫法(原文範例修正)
function getMonthNum($st, $et): int {
$sy = date('Y', $st); $sm = date('n', $st);
$ey = date('Y', $et); $em = date('n', $et);
return ($ey - $sy) * 12 + $em - $sm;
}
<?php
/**
* 計算兩個日期相差幾天 (YYYY-MM-DD 格式)
*/
function diffDays($date1, $date2): int {
$d1 = strtotime($date1);
$d2 = strtotime($date2);
return abs(intdiv($d1 - $d2, DAY));
}
echo diffDays('2010-08-11', '2010-08-16'); // 5
echo diffDays('2010-08-16', '2010-08-11'); // 5 (abs)
<?php
$start = new DateTime('2010-12-11 11:40:00');
$end = new DateTime('2012-12-12 11:45:09');
$diff = $start->diff($end); // DateInterval 物件
echo "{$diff->y}年 {$diff->m}月 {$diff->d}天 ";
echo "{$diff->h}時 {$diff->i}分 {$diff->s}秒";
// 輸出:2年 0月 1天 0時 5分 9秒
// 總天數
echo $diff->days; // 731
// 格式化輸出
echo $diff->format('%Y年 %m月 %d天 %h時 %i分 %s秒');
優點:自動處理閏年、月份天數差異、DST、時區,官方推薦做法。
<?php
date_default_timezone_set('Asia/Taipei');
$start = strtotime('2024-01-01 00:00:00');
$end = strtotime('2024-01-02 00:00:00');
// 正常情況下差 86400 秒
// 但若跨越 DST 切換日(部分時區),實際秒數可能是 82800 或 90000
// 解決:全部用 UTC 計算
date_default_timezone_set('UTC');
$start = strtotime('2024-01-01 00:00:00');
$end = strtotime('2024-01-02 00:00:00');
// 保證 86400
| 需求 | 推薦函數/寫法 |
|---|---|
| 相差幾秒/分/時/天 | diffTime() 或 DateTime::diff() |
| 相差幾月 (忽略日) | diffMonths() |
| 精確年齡 (年/月/日) | DateTime::diff() |
| 倒數計時器 | 前端 JS 用 Date.now() 差值,後端只提供 UTC 截止時間戳 |
| 排程判斷「是否超過 N 天」 | (time() - $created) > N * DAY |
time() 相減 + 整除/取模。date('Y')/date('n') 算術。DateTime::diff(),內建處理閏年、閏秒、時區。time()) 或 ISO 8601 字串 (DateTime::format('c'))。