核心日期函數速查表
| 函數 | 說明 | 範例 | 結果類型 |
SYSDATE | 資料庫伺服器當前日期時間 | SYSDATE | DATE |
SYSTIMESTAMP | 含時區、毫秒的當前時間 | SYSTIMESTAMP | TIMESTAMP WITH TZ |
CURRENT_DATE | Session 時區當前日期 | CURRENT_DATE | DATE |
CURRENT_TIMESTAMP(p) | Session 時區當前時間戳,p=精度(0-9) | CURRENT_TIMESTAMP(3) | TIMESTAMP WITH TZ |
LOCALTIMESTAMP(p) | Session 時區當前時間戳 (無時區) | LOCALTIMESTAMP(6) | TIMESTAMP |
DBTIMEZONE | 資料庫時區位移 | DBTIMEZONE | VARCHAR2 |
SESSIONTIMEZONE | Session 時區位移 | SESSIONTIMEZONE | VARCHAR2 |
ADD_MONTHS(d, n) | 日期加減 n 月 | ADD_MONTHS(SYSDATE, -3) | DATE |
MONTHS_BETWEEN(d1, d2) | 兩日期月差 (含小數) | MONTHS_BETWEEN(d1,d2) | NUMBER |
LAST_DAY(d) | 該月最後一天 | LAST_DAY(SYSDATE) | DATE |
NEXT_DAY(d, weekday) | 日期 d 後第一個指定星期 | NEXT_DAY(SYSDATE,'FRIDAY') | DATE |
ROUND(d, fmt) | 日期捨入 (fmt: YEAR/MONTH/DD/DAY...) | ROUND(SYSDATE,'MONTH') | DATE |
TRUNC(d, fmt) | 日期截斷 | TRUNC(SYSDATE,'YEAR') | DATE |
EXTRACT(field FROM d) | 擷取日期欄位 | EXTRACT(HOUR FROM SYSTIMESTAMP) | NUMBER |
NEW_TIME(d, tz1, tz2) | 舊版時區轉換 (已棄用) | NEW_TIME(d,'GMT','PST') | DATE |
FROM_TZ(ts, tz) | TIMESTAMP 加上時區 | FROM_TZ(ts,'Asia/Taipei') | TIMESTAMP WITH TZ |
TO_CHAR(d, fmt, nls) | 日期轉字串 | TO_CHAR(d,'YYYY-MM-DD HH24:MI:SS') | VARCHAR2 |
TO_DATE(s, fmt, nls) | 字串轉日期 | TO_DATE('2023-01-01','YYYY-MM-DD') | DATE |
TO_TIMESTAMP(s, fmt) | 字串轉時間戳 | TO_TIMESTAMP('2023-01-01 12:00:00.123','YYYY-MM-DD HH24:MI:SS.FF') | TIMESTAMP |
CAST(x AS type) | ANSI 標準型別轉換 | CAST(SYSDATE AS TIMESTAMP) | 目標類型 |
日期格式化元素完整表
| 元素 | 說明 | 範例 |
| YYYY / YY / RRRR / RR | 年份 (RR 自動判斷世紀) | 2023 / 23 |
| MM / MON / MONTH | 月份數字/縮寫/全名 | 01 / JAN / JANUARY |
| DD / DDD | 月內/年內第幾天 | 15 / 045 |
| HH24 / HH / HH12 | 24/12 小時制 | 14 / 02 |
| MI / SS / SSSSS | 分/秒/午夜至今秒數 | 30 / 59 / 50400 |
| FF / FF1..FF9 | 毫秒/微秒/奈秒 (1-9 位) | .123456789 |
| DAY / DY / D | 星期全名/縮寫/數字(1-7) | MONDAY / MON / 2 |
| AM / PM / A.M. / P.M. | 上午/下午標記 | PM |
| TZD / TZH / TZM / TZR | 時區縮寫/時差時/時差分/區域名 | CST / +08 / 00 / Asia/Taipei |
| IW / IYYY | ISO 週數/年份 | 03 / 2023 |
| W / WW | 月內/年內週數 | 2 / 03 |
| Q | 季度 (1-4) | 1 |
| RM | 羅馬數字月份 | I |
| SP / SPTH | 拼寫數字/序數 | TWENTY-THREE / TWENTY-THIRD |
間隔運算 (INTERVAL) - 10g+ 推薦
-- 年月間隔
SYSDATE - INTERVAL '2' YEAR
SYSDATE - INTERVAL '6' MONTH
SYSDATE - INTERVAL '2-6' YEAR TO MONTH
-- 日時分秒間隔
SYSDATE - INTERVAL '7' DAY
SYSDATE - INTERVAL '3' HOUR
SYSDATE - INTERVAL '30' MINUTE
SYSDATE - INTERVAL '45' SECOND
SYSDATE - INTERVAL '1 2:30:45' DAY TO SECOND
-- 運算
SYSDATE + INTERVAL '1' DAY - INTERVAL '2' HOUR
INTERVAL '2' HOUR * 3 -- 6 小時
常用實戰模式
1. 本月第一天/最後一天
TRUNC(SYSDATE, 'MM') -- 本月 1 號 00:00:00
LAST_DAY(TRUNC(SYSDATE, 'MM')) -- 本月最後一天 00:00:00
LAST_DAY(SYSDATE) + 1 - 1/86400 -- 本月最後一天 23:59:59
2. 本年第一天/最後一天
TRUNC(SYSDATE, 'YYYY')
ADD_MONTHS(TRUNC(SYSDATE, 'YYYY'), 12) - 1/86400
3. 週一為週首日
TRUNC(SYSDATE, 'IW') -- ISO 週首日 (週一)
NEXT_DAY(TRUNC(SYSDATE) - 7, 'MONDAY') -- 相容舊版
4. 年齡/年資計算
-- 年齡 (滿歲)
FLOOR(MONTHS_BETWEEN(SYSDATE, birth_date) / 12)
-- 精確年月日
TRUNC(MONTHS_BETWEEN(SYSDATE, birth_date)/12) || '歲 ' ||
MOD(TRUNC(MONTHS_BETWEEN(SYSDATE, birth_date)), 12) || '月'
5. 毫秒/微秒精度
-- 當前毫秒
TO_CHAR(SYSTIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.FF3')
-- 程式執行時間 (百萬分之一秒)
DECLARE
l_start NUMBER := DBMS_UTILITY.GET_TIME; -- 百分之一秒
BEGIN
-- 待測程式碼
DBMS_OUTPUT.PUT_LINE('耗時: ' || (DBMS_UTILITY.GET_TIME - l_start)/100 || ' 秒');
END;
6. 時區轉換最佳實踐
-- 正確方式:使用 TIMESTAMP WITH TIME ZONE
SELECT FROM_TZ(CAST(SYSDATE AS TIMESTAMP), 'UTC') AT TIME ZONE 'Asia/Taipei'
FROM DUAL;
-- Session 時區影響
ALTER SESSION SET TIME_ZONE = 'Asia/Taipei';
SELECT CURRENT_TIMESTAMP FROM DUAL; -- 顯示台灣時間
效能與最佳實踐
- 索引欄位勿加函數:
WHERE TRUNC(dt) = TRUNC(SYSDATE) 導致全表掃描 → 改用 WHERE dt >= TRUNC(SYSDATE) AND dt < TRUNC(SYSDATE)+1
- 統一用 TIMESTAMP WITH TIME ZONE:跨時區系統避免時區混淆
- NLS 參數明確化:
TO_CHAR(d, 'fmt', 'NLS_DATE_LANGUAGE=AMERICAN') 避免 Session 干擾
- 分區表按日期分區:大量歷史資料查詢效能大增
- 避免隱含轉換:
WHERE date_col = '2023-01-01' → WHERE date_col = DATE '2023-01-01'
常見陷阱
| 陷阱 | 錯誤寫法 | 正確寫法 |
| 隱含字串轉日期 | WHERE d = '2023-01-01' | WHERE d = DATE '2023-01-01' |
| 索引失效 | WHERE TRUNC(d) = TRUNC(SYSDATE) | WHERE d >= TRUNC(SYSDATE) AND d < TRUNC(SYSDATE)+1 |
| 月份加減邊界 | ADD_MONTHS('31-JAN-2023',1) → 28-FEB | 業務確認是否需調整為月底 |
| 時區混淆 | SYSDATE 跨時區比較 | 統一用 SYSTIMESTAMP 或 CURRENT_TIMESTAMP |
| 閏秒/夏令時間 | 忽略 DST 變更 | 用 TIMESTAMP WITH TIME ZONE + 時區資料庫 |