日期運算是日常開發高頻操作。Oracle 提供 ADD_MONTHS、數值運算(以天為單位)、INTERVAL 語法三種方式,本文整理年/月/週/日/時/分/秒各粒度的加減法標準寫法。
ADD_MONTHS 處理月末邊界(如 1/31 + 1 月 = 2/28 或 2/29)| 粒度 | 加法 | 減法 | 說明 |
|---|---|---|---|
| 年 | ADD_MONTHS(dt, 12) | ADD_MONTHS(dt, -12) | 跨年、閏年自動處理 |
| 月 | ADD_MONTHS(dt, 1) | ADD_MONTHS(dt, -1) | 月末自動調整至目標月最後一天 |
| 週 | dt + 7 | dt - 7 | 以天為單位運算 |
| 日 | dt + 1 | dt - 1 | 最基本單位 |
| 時 | dt + 1/24 | dt - 1/24 | 1/24 天 = 1 小時 |
| 分 | dt + 1/24/60 | dt - 1/24/60 | 1/1440 天 = 1 分鐘 |
| 秒 | dt + 1/24/60/60 | dt - 1/24/60/60 | 1/86400 天 = 1 秒 |
-- 年
SELECT SYSDATE, ADD_MONTHS(SYSDATE, 12) AS plus_1_year FROM dual;
SELECT SYSDATE, ADD_MONTHS(SYSDATE, -12) AS minus_1_year FROM dual;
-- 月
SELECT SYSDATE, ADD_MONTHS(SYSDATE, 1) AS plus_1_month FROM dual;
SELECT SYSDATE, ADD_MONTHS(SYSDATE, -1) AS minus_1_month FROM dual;
-- 週
SELECT SYSDATE, SYSDATE + 7 AS plus_1_week FROM dual;
SELECT SYSDATE, SYSDATE - 7 AS minus_1_week FROM dual;
-- 日
SELECT SYSDATE, SYSDATE + 1 AS plus_1_day FROM dual;
SELECT SYSDATE, SYSDATE - 1 AS minus_1_day FROM dual;
-- 時
SELECT SYSDATE, SYSDATE + 1/24 AS plus_1_hour FROM dual;
SELECT SYSDATE, SYSDATE - 1/24 AS minus_1_hour FROM dual;
-- 分
SELECT SYSDATE, SYSDATE + 1/24/60 AS plus_1_min FROM dual;
SELECT SYSDATE, SYSDATE - 1/24/60 AS minus_1_min FROM dual;
-- 秒
SELECT SYSDATE, SYSDATE + 1/24/60/60 AS plus_1_sec FROM dual;
SELECT SYSDATE, SYSDATE - 1/24/60/60 AS minus_1_sec FROM dual;
-- 年/月
SELECT SYSDATE + INTERVAL '1' YEAR FROM dual;
SELECT SYSDATE - INTERVAL '1' MONTH FROM dual;
-- 日/時/分/秒
SELECT SYSDATE + INTERVAL '7' DAY FROM dual;
SELECT SYSDATE + INTERVAL '1' HOUR FROM dual;
SELECT SYSDATE + INTERVAL '30' MINUTE FROM dual;
SELECT SYSDATE + INTERVAL '45' SECOND FROM dual;
-- 複合間隔
SELECT SYSDATE + INTERVAL '1-6' YEAR TO MONTH FROM dual; -- 1 年 6 月
SELECT SYSDATE + INTERVAL '3 12:30:15' DAY TO SECOND FROM dual; -- 3 天 12:30:15
SELECT TO_CHAR(SYSDATE + 1, 'YYYY-MM-DD HH24:MI:SS') AS tomorrow FROM dual;
SELECT TO_CHAR(ADD_MONTHS(SYSDATE, 3), 'YYYY-MM') AS three_months_later FROM dual;
ADD_MONTHS('31-JAN-2023', 1) → 28-FEB-2023(非 31 日),業務邏輯需確認是否符合預期TIMESTAMP WITH TIME ZONE + INTERVAL1/24/60/60 為循環小數,極高精度需求改用 INTERVAL 或 NUMTODSINTERVALWHERE dt + 1 > SYSDATE 導致函數運算,改寫為 WHERE dt > SYSDATE - 1SYSTIMESTAMP、INTERVAL、NUMTODSINTERVAL 避免隱含轉型Oracle 無內建工作日函數,需自訂函數或使用 Calendar 表:
CREATE TABLE biz_calendar (
cal_date DATE PRIMARY KEY,
is_workday NUMBER(1) CHECK (is_workday IN (0,1))
);
-- 取得 N 個工作日後的日期
SELECT MIN(cal_date) FROM (
SELECT cal_date FROM biz_calendar
WHERE cal_date > :start_date AND is_workday = 1
ORDER BY cal_date
) WHERE ROWNUM <= :n;