DATEDIFF(datepart, start, end):回傳兩日期間的日期部件差值(整數)。DATEADD(datepart, number, date):在日期上加減指定間隔,回傳新日期。關鍵思維:**以「1900-01-01 00:00:00.000」為基準點,計算間隔數,再加減得到目標日期。**
| 需求 | T-SQL 公式 | 說明 |
|---|---|---|
| 本月第一天 | DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) | 間隔月數加到基準點 |
| 本週一(週一為週首) | DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0) | 依 @@DATEFIRST 決定週首,預設週日 |
| 今年第一天 | DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0) | |
| 本季第一天 | DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0) | |
| 今天零點(去除時間) | DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0) | 等同 CAST(GETDATE() AS DATE) (SQL 2008+) |
| 上月最後一天 | DATEADD(MILLISECOND, -3, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) | 本月第一天 - 3ms(SQL Server 精度 3.33ms) |
| 去年最後一天 | DATEADD(MILLISECOND, -3, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)) | |
| 本月最後一天 | DATEADD(MILLISECOND, -3, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())+1, 0)) | 下月第一天 - 3ms |
| 今年最後一天 | DATEADD(MILLISECOND, -3, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE())+1, 0)) | |
| 本月第一個週一 | DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEADD(DAY, 6-DATEPART(DAY, GETDATE()), GETDATE())), 0) | 以本月 6 號為基準推算 |
-- 最近 30 天
WHERE create_date >= DATEADD(DAY, -30, CAST(GETDATE() AS DATE))
-- 本月迄今
WHERE create_date >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)
-- 上月完整範圍
WHERE create_date >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0)
AND create_date < DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)
-- 本季度
WHERE create_date >= DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0)
AND create_date < DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE())+1, 0)
-- 方法 A:下月第一天 - 本月第一天
DECLARE @m INT = 2; -- 二月
SELECT DATEDIFF(DAY,
DATEADD(MONTH, @m-1, DATEADD(YEAR, DATEDIFF(YEAR,0,GETDATE()),0)),
DATEADD(MONTH, @m, DATEADD(YEAR, DATEDIFF(YEAR,0,GETDATE()),0))
);
-- 方法 B:用本月最後一天的 DAY()
SELECT DAY(DATEADD(MILLISECOND, -3,
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())+1, 0)));
-- 方法 A:二月天數
SELECT CASE DAY(DATEADD(MONTH, 2,
DATEADD(MILLISECOND, -3, DATEADD(YEAR, DATEDIFF(YEAR,0,GETDATE()),0))))
WHEN 28 THEN '平年' ELSE '閏年' END;
-- 方法 B:直接計算二月天數
SELECT CASE DATEDIFF(DAY,
CAST(YEAR(GETDATE()) AS VARCHAR)+'-02-01',
DATEADD(MONTH, 1, CAST(YEAR(GETDATE()) AS VARCHAR)+'-02-01'))
WHEN 28 THEN '平年' ELSE '閏年' END;
SELECT DATENAME(WEEKDAY, GETDATE()); -- 如 'Monday'
DECLARE @q_start SMALLDATETIME = DATEADD(QUARTER, DATEDIFF(QUARTER,0,GETDATE()),0);
SELECT DATEDIFF(DAY, @q_start, DATEADD(QUARTER, 1, @q_start));
DATE, TIME, DATETIME2, DATETIMEOFFSET 型別,CAST(GETDATE() AS DATE) 取代去除時間的技巧。EOMONTH(start_date [, month_offset]) (2012+) 直接取得月份最後一天:EOMONTH(GETDATE())、EOMONTH(GETDATE(), -1) (上月)。DATETRUNC(datepart, date) (2022+) 直接截斷至指定精度:DATETRUNC(MONTH, GETDATE()) 即本月第一天。WHERE dt >= @start AND dt < @end_next,避免時間精度邊界問題。SET DATEFIRST 或用不依賴週首的邏輯。掌握 DATEADD/DATEDIFF 間隔思維,配合新版便利函數,能優雅解決所有日期邊界計算需求。