MySQL 提供豐富的日期時間函數族,支援日期提取、運算、格式化、轉換等多維度操作。本文按功能分類整理 23 大核心函數,附帶語法、參數說明與實戰範例,作為開發與調優的速查手冊。
| 函數 | 功能 | 返回值範圍/示例 |
|---|---|---|
DAYOFWEEK(date) | 週索引(1=周日,7=周六),符合 ODBC 標準 | DAYOFWEEK('1998-02-03') → 3 |
WEEKDAY(date) | 週索引(0=周一,6=周日) | WEEKDAY('1997-10-04') → 5 |
DAYOFMONTH(date) | 月內天數 | 1~31 |
DAYOFYEAR(date) | 年內天數 | 1~366 |
MONTH(date) | 月份 | 1~12 |
DAYNAME(date) | 星期英文名 | 'Thursday' |
MONTHNAME(date) | 月份英文名 | 'February' |
QUARTER(date) | 季度 | 1~4 |
WEEK(date[,mode]) | 周數,mode=0 週日起算,mode=1 週一起算 | WEEK('1998-02-20',1) → 8 |
YEAR(date) | 年份(4 位) | 1000~9999 |
HOUR(time) | 小時 | 0~23 |
MINUTE(time) | 分鐘 | 0~59 |
SECOND(time) | 秒 | 0~59 |
| 函數 | 功能 | 示例 |
|---|---|---|
PERIOD_ADD(P,N) | 期間 P(YYMM/YYYYMM)加 N 月 | PERIOD_ADD(9801,2) → 199803 |
PERIOD_DIFF(P1,P2) | 兩期間月份差 | PERIOD_DIFF(9802,199703) → 11 |
注意: 期間參數非日期類型,僅用於月度統計場景(如財務報表)。
四個函數功能等價,推薦使用 DATE_ADD/DATE_SUB 語義更清晰。MySQL 3.23+ 支援 +/- 運算符重載。
| 類型關鍵字 | 含義 | expr 格式示例 |
|---|---|---|
| SECOND / MINUTE / HOUR / DAY / MONTH / YEAR | 單一單位 | 30、6 |
| MINUTE_SECOND | 分:秒 | '1:30' |
| HOUR_MINUTE | 時:分 | '2:30' |
| DAY_HOUR | 天 時 | '3 12' |
| YEAR_MONTH | 年-月 | '2-6' |
| HOUR_SECOND | 時:分:秒 | '1:30:45' |
| DAY_MINUTE | 天 時:分 | '3 12:30' |
| DAY_SECOND | 天 時:分:秒 | '3 12:30:45' |
-- 日期加 1 秒
SELECT DATE_ADD('1997-12-31 23:59:59', INTERVAL 1 SECOND); -- 1998-01-01 00:00:00
-- 日期加 1 天
SELECT '1997-12-31' + INTERVAL 1 DAY; -- 1998-01-01
-- 複合間隔:減去 1 天 1 時 1 分 1 秒
SELECT DATE_SUB('1998-01-01 00:00:00', INTERVAL '1 1:1:1' DAY_SECOND); -- 1997-12-30 22:58:59
-- 負間隔:減去 1 天 10 小時
SELECT DATE_ADD('1998-01-01 00:00:00', INTERVAL '-1 10' DAY_HOUR); -- 1997-12-30 14:00:00
-- 月末自動調整:1月30日加1個月→2月28日(非閏年)
SELECT DATE_ADD('1998-01-30', INTERVAL 1 MONTH); -- 1998-02-28
-- 提取組件
SELECT EXTRACT(YEAR_MONTH FROM '1999-07-02 01:02:03'); -- 199907
'1:10' DAY_SECOND 視為 MINUTE_SECOND)INTERVAL 關鍵字與類型不區分大小寫SELECT TO_DAYS('1997-10-07'); -- 729669(從 Year 0 起算天數)
SELECT FROM_DAYS(729669); -- '1997-10-07'
限制: 僅適用於格里曆(1582 年後),早期日期不可用。
| 符號 | 含義 | 示例 |
|---|---|---|
| %Y / %y | 4位/2位年份 | 1997 / 97 |
| %m / %c | 月份(01~12 / 1~12) | 02 / 2 |
| %d / %e | 日期(01~31 / 1~31) | 03 / 3 |
| %H / %k | 小時(00~23 / 0~23) | 22 / 22 |
| %i | 分鐘(00~59) | 23 |
| %S / %s | 秒(00~59) | 00 |
| %W / %a | 星期全稱/縮寫 | Saturday / Sat |
| %M / %b | 月份全稱/縮寫 | October / Oct |
| %r / %T | 12h/24h 時間 | 10:23:00 PM / 22:23:00 |
| %p | AM/PM | PM |
| %j | 年內天數(001~366) | 277 |
TIME_FORMAT 僅支援時分秒相關符號,其他符號返回 NULL/0。
SELECT DATE_FORMAT('1997-10-04 22:23:00', '%W %M %Y'); -- 'Saturday October 1997'
SELECT DATE_FORMAT('1997-10-04 22:23:00', '%H:%i:%s'); -- '22:23:00'
SELECT DATE_FORMAT('1997-10-04 22:23:00', '%D %y %a %d %m %b %j'); -- '4th 97 Sat 04 10 Oct 277'
| 函數 | 返回格式(字符串/數字上下文) | 別名 |
|---|---|---|
CURDATE() | 'YYYY-MM-DD' / YYYYMMDD | CURRENT_DATE |
CURTIME() | 'HH:MM:SS' / HHMMSS | CURRENT_TIME |
NOW() | 'YYYY-MM-DD HH:MM:SS' / YYYYMMDDHHMMSS | SYSDATE()、CURRENT_TIMESTAMP |
注意: NOW() 在存儲過程/觸發器中執行開始時固定;SYSDATE() 實時獲取,主從複製場景下行為不同(5.6+ 可通過 sysdate-is-now 統一)。
| 函數 | 功能 | 示例 |
|---|---|---|
UNIX_TIMESTAMP() | 當前/指定日期轉秒數(從 1970-01-01 UTC) | UNIX_TIMESTAMP('1997-10-04 22:23:00') → 875996580 |
FROM_UNIXTIME(ts[,fmt]) | 秒數轉日期字符串,可帶格式 | FROM_UNIXTIME(875996580, '%Y %D %M %h:%i:%s %x') → '1997 23rd December 03:43:30 x' |
對 TIMESTAMP 列調用 UNIX_TIMESTAMP 直接讀取內部存儲值,無隱式轉換開銷。
SELECT SEC_TO_TIME(2378); -- '00:39:38'
SELECT TIME_TO_SEC('22:23:00'); -- 80580
WHERE DATE(create_time) = '2023-01-01'),改用範圍查詢 WHERE create_time >= '2023-01-01' AND create_time < '2023-01-02' 利用索引。SET time_zone)、系統層三者時區保持一致,避免 NOW()/UNIX_TIMESTAMP 跨時區偏差。DATE_FORMAT 在大數據量報表中開銷較大,可考慮應用層格式化或物化視圖預計算。