首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL DATE_ADD 函數實戰指南:時間日期運算的完整場景覆蓋

     編輯:MySQL 綜合教學

MySQL DATE_ADD 函數實戰指南:時間日期運算的完整場景覆蓋

DATE_ADD() 是 MySQL 中進行日期時間加減運算的核心函數,支援從微秒到年份的所有時間單位。本文提供完整的語法參考、常見業務場景範例、效能考量與替代方案,作為開發與調試的速查手冊。

一、語法結構

DATE_ADD(date, INTERVAL expr unit)
-- 等價別名:ADDDATE(date, INTERVAL expr unit)

-- 參數說明:
-- date: 合法的日期/時間表達式 (DATE, DATETIME, TIMESTAMP, 字串)
-- expr: 數值運算式,可為負數(實現減法)
-- unit: 時間單位關鍵字 (MICROSECOND, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, YEAR 等)

二、完整單位操作速查表

單位加法範例減法範例說明
MICROSECONDDATE_ADD(NOW(), INTERVAL 1 MICROSECOND)DATE_ADD(NOW(), INTERVAL -1 MICROSECOND)微秒級,高精度日誌分析
SECONDDATE_ADD(NOW(), INTERVAL 30 SECOND)DATE_ADD(NOW(), INTERVAL -30 SECOND)秒級,Token 過期、緩存 TTL
MINUTEDATE_ADD(NOW(), INTERVAL 15 MINUTE)DATE_ADD(NOW(), INTERVAL -15 MINUTE)分鐘級,定時任務窗口
HOURDATE_ADD(NOW(), INTERVAL 2 HOUR)DATE_ADD(NOW(), INTERVAL -2 HOUR)小時級,跨時區轉換、統計窗口
DAYDATE_ADD(CURDATE(), INTERVAL 1 DAY)DATE_ADD(CURDATE(), INTERVAL -1 DAY)天級,日報、留存計算
WEEKDATE_ADD(CURDATE(), INTERVAL 1 WEEK)DATE_ADD(CURDATE(), INTERVAL -1 WEEK)週級,週報、同比環比
MONTHDATE_ADD(CURDATE(), INTERVAL 1 MONTH)DATE_ADD(CURDATE(), INTERVAL -1 MONTH)月級,月報、帳單週期
QUARTERDATE_ADD(CURDATE(), INTERVAL 1 QUARTER)DATE_ADD(CURDATE(), INTERVAL -1 QUARTER)季度級,財報、季度規劃
YEARDATE_ADD(CURDATE(), INTERVAL 1 YEAR)DATE_ADD(CURDATE(), INTERVAL -1 YEAR)年級,周年慶、長期趨勢

三、複合單位與特殊語法

-- 複合間隔:日 + 時間
DATE_ADD('2024-01-15 10:30:00', INTERVAL '1 12:30:45' DAY_SECOND)
-- 結果:2024-01-16 23:00:45

-- 年月複合
DATE_ADD('2024-01-15', INTERVAL '1-6' YEAR_MONTH)
-- 結果:2025-07-15

-- 等價減法函數
DATE_SUB(date, INTERVAL expr unit)
-- 範例:DATE_SUB(NOW(), INTERVAL 1 DAY) 等同於 DATE_ADD(NOW(), INTERVAL -1 DAY)

四、核心業務場景實戰

場景 1:動態時間範圍查詢(報表/儀表板)

-- 近 30 天訂單
SELECT * FROM orders 
WHERE created_at >= DATE_ADD(CURDATE(), INTERVAL -30 DAY);

-- 本月迄今 (MTD)
SELECT * FROM sales 
WHERE sale_date >= DATE_ADD(LAST_DAY(DATE_SUB(CURDATE(), INTERVAL 1 MONTH)), INTERVAL 1 DAY)
  AND sale_date < DATE_ADD(LAST_DAY(CURDATE()), INTERVAL 1 DAY);

場景 2:排程與過期時間計算

-- Token 2 小時後過期
UPDATE user_tokens SET expires_at = DATE_ADD(NOW(), INTERVAL 2 HOUR) WHERE user_id = 1001;

-- 緩存 15 分鐘 TTL
INSERT INTO cache (key, value, expire_at) 
VALUES ('key1', 'data', DATE_ADD(NOW(), INTERVAL 15 MINUTE));

場景 3:業務週期邊界計算

-- 本月第一天 00:00:00
SELECT DATE_ADD(LAST_DAY(DATE_SUB(CURDATE(), INTERVAL 1 MONTH)), INTERVAL 1 DAY);

-- 本月最後一天 23:59:59
SELECT DATE_SUB(DATE_ADD(LAST_DAY(CURDATE()), INTERVAL 1 DAY), INTERVAL 1 SECOND);

-- 下個季度第一天
SELECT DATE_ADD(LAST_DAY(DATE_ADD(CURDATE(), INTERVAL (3 - MONTH(CURDATE()) % 3) MONTH)), INTERVAL 1 DAY);

場景 4:相對時間錨點(避免硬編碼日期)

-- 昨天同一時間
SELECT DATE_ADD(NOW(), INTERVAL -1 DAY);

-- 上週同一天
SELECT DATE_ADD(CURDATE(), INTERVAL -1 WEEK);

-- 去年今日
SELECT DATE_ADD(CURDATE(), INTERVAL -1 YEAR);

五、效能與索引關鍵警示

⚠️ 索引失效陷阱
WHERE created_at >= DATE_ADD(NOW(), INTERVAL -30 DAY) 無法使用索引,因為 NOW() 非常數,優化器無法在編譯期確定範圍。

最佳實踐:應用層計算常數值

-- 應用層 (PHP/Java/Go 等) 計算好具體日期時間字串
-- SQL 僅接收常數
WHERE created_at >= '2024-01-15 00:00:00'  -- 可命中索引

-- 或使用預處理語句綁定參數
PREPARE stmt FROM 'SELECT * FROM orders WHERE created_at >= ?';
SET @start_date = DATE_ADD(CURDATE(), INTERVAL -30 DAY);  -- 會話變數在 8.0+ 可被優化器識別
EXECUTE stmt USING @start_date;

六、邊界情況與版本差異

  1. 月份溢位處理:DATE_ADD('2024-01-31', INTERVAL 1 MONTH) → 2024-02-29 (閏年) / 2024-02-28 (平年)。MySQL 自動截取到目標月最後一天。
  2. TIMESTAMP 範圍限制:1970-01-01 00:00:01 UTC 到 2038-01-19 03:14:07 UTC。跨越此範圍運算會返回 NULL。**長期業務請用 DATETIME**。
  3. 時區影響:NOW() 返回當前會話時區時間,UTC_TIMESTAMP() 返回 UTC。跨時區應用建議統一儲存 UTC,應用層轉換。
  4. INTERVAL 運算式支援欄位引用:DATE_ADD(created_at, INTERVAL valid_days DAY),但同樣導致索引失效。

七、替代方案對比

函數/語法適用場景優點缺點
DATE_ADD通用日期加減語義清晰、單位豐富索引失效風險
+ INTERVAL (8.0+)簡潔寫法created_at + INTERVAL 1 DAY 可讀性高同樣索引問題
TIMESTAMPADD需返回 TIMESTAMP單位為數字常數 (1=SECOND...)語義較晦澀
應用層計算高頻查詢、大表**索引友好**、跨資料庫可移植需應用層邏輯

掌握 DATE_ADD 的全單位支援與複合語法,能極大簡化時間相關業務邏輯。但**生產環境高頻查詢務必將動態計算下沉到應用層**,保持 SQL 參數常數化,才能充分發揮索引效能。將本指南作為團隊時間運算規範附件,統一開發標準。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved