日期運算貫穿業務系統始終。本文分兩部份:第一部份匯總秒/分/時/天/月/年加減、邊界日期(月末、周初、年末)、格式模板;第二部份給出生產級工作日計算算法(排除週末),附帶測試數據與邏輯解析,可直接嵌入存儲過程或報表 SQL。
| 需求 | 表達式 |
|---|---|
| +5 秒 | SYSDATE + 5/24/60/60 |
| +5 分鐘 | SYSDATE + 5/24/60 |
| +5 小時 | SYSDATE + 5/24 |
| +5 天 | SYSDATE + 5 |
| -5 月 | ADD_MONTHS(SYSDATE, -5) |
| -5 年 | ADD_MONTHS(SYSDATE, -60) |
| 需求 | SQL |
|---|---|
| 上月末 | LAST_DAY(ADD_MONTHS(SYSDATE, -1)) |
| 本月最後一秒 | TRUNC(ADD_MONTHS(SYSDATE,1),'MM') - 1/24/60/60 |
| 本周一 | TRUNC(SYSDATE, 'DAY') + 1 |
| 年初至今天數 | CEIL(SYSDATE - TRUNC(SYSDATE, 'YEAR')) |
| 今年第幾周 | TO_CHAR(SYSDATE, 'FMWW') |
| 本月第幾周 | TO_CHAR(SYSDATE,'WW') - TO_CHAR(TRUNC(SYSDATE,'MM'),'WW') + 1 |
| 本月天數 | TO_CHAR(LAST_DAY(SYSDATE), 'DD') |
| 今年天數 | ADD_MONTHS(TRUNC(SYSDATE,'YEAR'),12) - TRUNC(SYSDATE,'YEAR') |
| 下個周一 | NEXT_DAY(SYSDATE, 'MONDAY') |
-- 假設日期無時間分量,否則所有日期前加 TRUNC
CREATE TABLE t (s DATE, e DATE);
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD';
INSERT INTO t VALUES ('2003-03-01','2003-03-03');
INSERT INTO t VALUES ('2003-03-02','2003-03-03');
INSERT INTO t VALUES ('2003-03-07','2003-03-08');
INSERT INTO t VALUES ('2003-03-07','2003-03-09');
INSERT INTO t VALUES ('2003-03-05','2003-03-07');
INSERT INTO t VALUES ('2003-02-01','2003-03-31');
SELECT s, e,
e - s + 1 AS total_days,
TRUNC((e - s + 1)/7)*5 +
LENGTH(REPLACE(SUBSTR('01111100111110',
TO_CHAR(s,'D'), MOD(e-s+1,7)), '0','')) AS work_days
FROM t;
DROP TABLE t;
TRUNC((天數)/7)*5,每周 5 個工作日。'01111100111110' 為 14 位雙周掩碼
TO_CHAR(s,'D') 返回 1(周日)~7(周六),作為掩碼起始索引。MOD(天數,7) 為餘數天數。SUBSTR 截取片段 → REPLACE(...,'0','') 移除周末 → LENGTH 剩餘長度即工作日數。該算法無需日歷表,純 SQL 實現,性能極高,適合百萬級報表實時計算。