日期時間處理是資料庫開發的高頻需求。MySQL 提供了豐富的內建函數,涵蓋提取、運算、格式化、時區轉換等場景。本文系統整理核心函數,並附實戰範例,助你高效處理時間數據。
| 函數 | 說明 | 範例 | 結果 |
|---|---|---|---|
| DAYOFWEEK(date) | 星期索引(1=週日...7=週六) | DAYOFWEEK('1998-02-03') | 3 |
| WEEKDAY(date) | 星期索引(0=週一...6=週日) | WEEKDAY('1997-10-04') | 5 |
| DAYOFMONTH(date) | 月份中的日期(1-31) | DAYOFMONTH('1998-02-03') | 3 |
| DAYOFYEAR(date) | 年份中的天數(1-366) | DAYOFYEAR('1998-02-03') | 34 |
| MONTH(date) | 月份(1-12) | MONTH('1998-02-03') | 2 |
| DAYNAME(date) | 星期名稱 | DAYNAME('1998-02-05') | Thursday |
| MONTHNAME(date) | 月份名稱 | MONTHNAME('1998-02-05') | February |
| QUARTER(date) | 季度(1-4) | QUARTER('98-04-01') | 2 |
| WEEK(date[,mode]) | 週數,mode=0 週日起算,1 週一起算 | WEEK('1998-02-20',1) | 8 |
| YEAR(date) | 年份(1000-9999) | YEAR('98-02-03') | 1998 |
| HOUR(time) | 小時(0-23) | HOUR('10:05:03') | 10 |
| MINUTE(time) | 分鐘(0-59) | MINUTE('10:05:03') | 5 |
| SECOND(time) | 秒數(0-59) | SECOND('10:05:03') | 3 |
PERIOD_ADD(P, N):P 為 YYMM 或 YYYYMM 格式,增加 N 月。PERIOD_ADD(9801, 2) → 199803PERIOD_DIFF(P1, P2):返回兩期間相差月數。PERIOD_DIFF(9802, 199703) → 11語法:DATE_ADD(date, INTERVAL expr type)
type 關鍵字與 expr 格式對應表:
| type | 含義 | expr 格式 |
|---|---|---|
| SECOND | 秒 | SECONDS |
| MINUTE | 分 | MINUTES |
| HOUR | 時 | HOURS |
| DAY | 天 | DAYS |
| MONTH | 月 | MONTHS |
| YEAR | 年 | YEARS |
| MINUTE_SECOND | 分:秒 | "MINUTES:SECONDS" |
| HOUR_MINUTE | 時:分 | "HOURS:MINUTES" |
| DAY_HOUR | 天 時 | "DAYS HOURS" |
| YEAR_MONTH | 年-月 | "YEARS-MONTHS" |
| HOUR_SECOND | 時:分:秒 | "HOURS:MINUTES:SECONDS" |
| DAY_MINUTE | 天 時:分 | "DAYS HOURS:MINUTES" |
| DAY_SECOND | 天 時:分:秒 | "DAYS HOURS:MINUTES:SECONDS" |
實戰範例:
SELECT DATE_ADD('1997-12-31 23:59:59', INTERVAL 1 SECOND); -- 1998-01-01 00:00:00
SELECT DATE_ADD('1997-12-31 23:59:59', INTERVAL 1 DAY); -- 1998-01-01 23:59:59
SELECT DATE_ADD('1998-01-01', INTERVAL -1 MONTH); -- 1997-12-01
SELECT DATE_SUB('1998-01-02', INTERVAL 31 DAY); -- 1997-12-02
SELECT '1997-12-31 23:59:59' + INTERVAL 1 SECOND; -- 簡寫語法(3.23+)
注意: 若 expr 位數不足,MySQL 會假設高位缺失。如 DAY_SECOND 類型傳 "1:10" 會被視為 MINUTE_SECOND(1分10秒),而非 1天10秒。
| 函數 | 說明 | 範例 |
|---|---|---|
| TO_DAYS(date) | 日期轉絕對天數(從 year 0 起) | TO_DAYS('1997-10-07') → 729669 |
| FROM_DAYS(N) | 天數轉日期 | FROM_DAYS(729669) → '1997-10-07' |
| UNIX_TIMESTAMP([date]) | 日期轉 Unix 時間戳(秒) | UNIX_TIMESTAMP('1997-10-04 22:23:00') → 875996580 |
| FROM_UNIXTIME(ts[,fmt]) | 時間戳轉日期,可帶格式 | FROM_UNIXTIME(875996580, '%Y %M %d') |
| SEC_TO_TIME(sec) | 秒數轉 HH:MM:SS | SEC_TO_TIME(2378) → '00:39:38' |
| TIME_TO_SEC(time) | 時間轉總秒數 | TIME_TO_SEC('22:23:00') → 80580 |
限制: TO_DAYS/FROM_DAYS 不適用於 1582 年格里曆前的日期。
DATE_FORMAT(date, format) 常用格式符:
| 符號 | 含義 | 範例輸出 |
|---|---|---|
| %Y | 4位年份 | 1997 |
| %y | 2位年份 | 97 |
| %M | 月份全名 | October |
| %b | 月份縮寫 | Oct |
| %m | 月份(01-12) | 10 |
| %d | 日期(01-31) | 04 |
| %H | 小時(00-23) | 22 |
| %h/%I | 小時(01-12) | 10 |
| %i | 分鐘(00-59) | 23 |
| %S/%s | 秒(00-59) | 00 |
| %W | 星期全名 | Saturday |
| %a | 星期縮寫 | Sat |
| %r | 12小時制時間 | 10:23:00 PM |
| %T | 24小時制時間 | 22:23:00 |
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
TIME_FORMAT 僅支援時分秒相關格式符,其他返回 NULL/0。
| 函數 | 返回類型 | 格式(字串語境) | 格式(數值語境) |
|---|---|---|---|
| CURDATE() / CURRENT_DATE | DATE | YYYY-MM-DD | YYYYMMDD |
| CURTIME() / CURRENT_TIME | TIME | HH:MM:SS | HHMMSS |
| NOW() / SYSDATE() / CURRENT_TIMESTAMP | DATETIME | YYYY-MM-DD HH:MM:SS | YYYYMMDDHHMMSS |
差異: NOW() 在語句開始執行時固定;SYSDATE() 實時獲取,主從複制中行為不同。
SELECT * FROM `table`
WHERE TO_DAYS(NOW()) - TO_DAYS(`date_col`) <= 30;
-- 或更推薦使用索引友好的寫法:
SELECT * FROM `table`
WHERE `date_col` >= DATE_SUB(NOW(), INTERVAL 30 DAY);
00-69 → 2000-206970-99 → 1970-1999