專案中常遇到「找出最近 30 天文章」、「按月統計銷售額」、「判斷某筆記錄是否為今天」等日期比較需求。本文系統整理 MySQL 與 PHP 端的日期比較方法,涵蓋 Unix 時間戳、DATE/DATETIME/TIMESTAMP 型別、PHP DateTime 物件 三大體系的互轉與查詢技巧。
| 函數 | 用途 | 範例 |
|---|---|---|
FROM_UNIXTIME(ts) | 時間戳 → DATETIME | FROM_UNIXTIME(1705300000) → '2024-01-15 10:13:20' |
UNIX_TIMESTAMP(dt) | DATETIME → 時間戳 | UNIX_TIMESTAMP('2024-01-15') → 1705248000 |
DATE(FROM_UNIXTIME(ts)) | 時間戳 → DATE(僅日期) | DATE(FROM_UNIXTIME(ts)) = '2024-01-15' |
add_time 為 INT 時間戳)-- 1. 最近 30 天(含今天)
WHERE DATE(FROM_UNIXTIME(add_time)) >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
-- 2. 本月資料
WHERE YEAR(FROM_UNIXTIME(add_time)) = YEAR(NOW())
AND MONTH(FROM_UNIXTIME(add_time)) = MONTH(NOW())
-- 3. 今天資料
WHERE DATE(FROM_UNIXTIME(add_time)) = CURDATE()
-- 4. 指定日期範圍
WHERE FROM_UNIXTIME(add_time) BETWEEN '2024-01-01' AND '2024-01-31 23:59:59'
-- 5. 相對時間:N 天前
WHERE FROM_UNIXTIME(add_time) >= DATE_SUB(NOW(), INTERVAL 7 DAY)
SELECT
YEAR(FROM_UNIXTIME(add_time)) AS yr,
MONTH(FROM_UNIXTIME(add_time)) AS mo,
DAY(FROM_UNIXTIME(add_time)) AS dy,
COUNT(*) AS cnt
FROM orders
GROUP BY yr, mo, dy
ORDER BY yr DESC, mo DESC, dy DESC;
若欄位已為日期型別,直接使用,無需 FROM_UNIXTIME:
-- 最近 30 天
WHERE date_col >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
-- 本月
WHERE YEAR(date_col) = YEAR(CURDATE()) AND MONTH(date_col) = MONTH(CURDATE())
-- 今天
WHERE DATE(date_col) = CURDATE()
-- TO_DAYS 差值比較(舊寫法,效能較差)
WHERE TO_DAYS(NOW()) - TO_DAYS(date_col) <= 30
<?php
// 1. 現在時間
$now = new DateTime(); // 預設伺服器時區
$now->setTimezone(new DateTimeZone('Asia/Taipei')); // 設定時區
// 2. 時間戳 → DateTime
$ts = 1705300000;
$dt = DateTime::createFromFormat('U', $ts); // 或 new DateTime("@$ts")
$dt->setTimezone(new DateTimeZone('Asia/Taipei'));
// 3. DateTime → 時間戳
$timestamp = $dt->getTimestamp(); // 等同 $dt->format('U')
// 4. 格式化輸出
echo $dt->format('Y-m-d H:i:s'); // 2024-01-15 10:13:20
echo $dt->format('Y年m月d日'); // 2024年01月15日
// 5. 日期運算
$dt->modify('+7 days'); // 7 天后
$dt->modify('first day of this month'); // 本月第一天
$dt->modify('last day of -1 month'); // 上月最後一天
// 6. 比較兩個日期
$diff = $dt1->diff($dt2);
echo $diff->days; // 天數差
echo $diff->format('%R%a 天'); // +7 天 / -3 天
// 7. 判斷是否為今天
$today = new DateTime('today', new DateTimeZone('Asia/Taipei'));
if ($dt->format('Y-m-d') === $today->format('Y-m-d')) {
echo '是今天';
}
SET time_zone = '+00:00',PHP 預設時區設為 UTC(date_default_timezone_set('UTC')),僅在顯示層轉換使用者時區。date()、strtotime():舊函數易受時區、32 位元整數(2038 年問題)影響,一律改用 DateTime / DateTimeImmutable。setTimezone() 統一,或都轉為 UTC 時間戳比較整數。| 需求 | MySQL (時間戳) | MySQL (日期型別) | PHP DateTime |
|---|---|---|---|
| 最近 N 天 | DATE(FROM_UNIXTIME(ts)) >= DATE_SUB(CURDATE(), INTERVAL N DAY) | date_col >= DATE_SUB(CURDATE(), INTERVAL N DAY) | $dt >= (new DateTime('-N days'))->setTimezone('UTC') |
| 本月 | YEAR(FROM_UNIXTIME(ts))=YEAR(NOW()) AND MONTH(...)=MONTH(NOW()) | YEAR(date_col)=YEAR(CURDATE()) AND MONTH(date_col)=MONTH(CURDATE()) | $dt->format('Y-m') === (new DateTime())->format('Y-m') |
| 今天 | DATE(FROM_UNIXTIME(ts)) = CURDATE() | DATE(date_col) = CURDATE() | $dt->format('Y-m-d') === (new DateTime('today'))->format('Y-m-d') |
| 按月統計 | GROUP BY YEAR(FROM_UNIXTIME(ts)), MONTH(FROM_UNIXTIME(ts)) | GROUP BY YEAR(date_col), MONTH(date_col) | // PHP 端分組較不適用,交給 SQL |
日期比較的核心原則:資料庫層盡量用原生日期型別、儲存統一 UTC、查詢利用索引友善寫法(避免函數包裹欄位);PHP 層一律用 DateTimeImmutable、明確設定時區、避免舊式函數。時間戳雖便於跨語言傳遞,但查詢時須轉換導致無法使用索引,大量資料建議改用 DATETIME + 索引。