所有日期運算建基於 1900-01-01 (Day 0) 為基準點。掌握「間差 + 基準」模式即可推導所有相對日期。
-- 當期首日 (精確到日,時分秒歸零)
DATEADD(, DATEDIFF(, 0, @Date), 0)
-- 當期首日 (保留原時分秒)
DATEADD(DAY, 1 - DATEPART(DAY, @Date), @Date) -- 月首日保留時間
-- 當期末日
DATEADD(, 1 + DATEDIFF(, 0, @Date), 0) - 1 -- 通用:下期首日 - 1天
DATEADD(DAY, -1, DATEADD(, 1 + DATEDIFF(, 0, @Date), 0)) -- 等價
-- 上期首日
DATEADD(, -1 + DATEDIFF(, 0, @Date), 0)
DATEADD(, DATEDIFF(, 0, @Date) - 1, 0)
-- 下期首日
DATEADD(, 1 + DATEDIFF(, 0, @Date), 0)
| 需求 | 語法 (精確到日) | 語法 (保留時間) |
|---|---|---|
| 前一日 / 後一日 | DATEADD(DAY, -1, @Date) / DATEADD(DAY, 1, @Date) | 同左 |
| 本月首日 | DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date), 0) | DATEADD(DAY, 1-DATEPART(DAY,@Date), @Date) |
| 本月末日 | DATEADD(MONTH, 1+DATEDIFF(MONTH, 0, @Date), 0) - 1 | DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEADD(DAY, 1-DATEPART(DAY,@Date), @Date))) |
| 上月首日 | DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date)-1, 0) | DATEADD(MONTH, -1, DATEADD(DAY, 1-DATEPART(DAY,@Date), @Date)) |
| 上月末日 | DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date), 0) - 1 | DATEADD(DAY, -DATEPART(DAY,@Date), @Date) |
| 下月首日 | DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date)+1, 0) | DATEADD(MONTH, 1, DATEADD(DAY, 1-DATEPART(DAY,@Date), @Date)) |
| 下月末日 | DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date)+2, 0) - 1 | DATEADD(DAY, -1, DATEADD(MONTH, 2, DATEADD(DAY, 1-DATEPART(DAY,@Date), @Date))) |
| 本週首日 (週日) | DATEADD(WEEK, DATEDIFF(WEEK, -1, @Date), -1) | DATEADD(WEEKDAY, 1-DATEPART(WEEKDAY,@Date), @Date) *需 SET DATEFIRST 7 |
| 本週首日 (週一) | DATEADD(WEEK, DATEDIFF(WEEK, 0, @Date), 0) | 同上 *需 SET DATEFIRST 1 |
| 上週首日 (週日) | DATEADD(WEEK, -1+DATEDIFF(WEEK, -1, @Date), -1) | DATEADD(DAY, -6-DATEPART(WEEKDAY,@Date), @Date) *DATEFIRST 7 |
| 下週首日 (週日) | DATEADD(WEEK, 1+DATEDIFF(WEEK, -1, @Date), -1) | DATEADD(DAY, 8-DATEPART(WEEKDAY,@Date), @Date) *DATEFIRST 7 |
| 本年首日 | DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0) | 同左 |
| 本年末日 | DATEADD(YEAR, 1+DATEDIFF(YEAR, 0, @Date), 0) - 1 | 同左 |
| 上年首日 | DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date)-1, 0) | 同左 |
| 上年末日 | DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0) - 1 | 同左 |
| 下年首日 | DATEADD(YEAR, 1+DATEDIFF(YEAR, 0, @Date), 0) | 同左 |
| 下年末日 | DATEADD(YEAR, 1+DATEDIFF(YEAR, -1, @Date), -1) | 同左 |
| 本季首日 | DATEADD(QUARTER, DATEDIFF(QUARTER, 0, @Date), 0) | 同左 |
| 本季末日 | DATEADD(QUARTER, 1+DATEDIFF(QUARTER, 0, @Date), 0) - 1 | 同左 |
| 上季首日 | DATEADD(QUARTER, DATEDIFF(QUARTER, 0, @Date)-1, 0) | 同左 |
| 上季末日 | DATEADD(QUARTER, DATEDIFF(QUARTER, 0, @Date), 0) - 1 | 同左 |
| 下季首日 | DATEADD(QUARTER, 1+DATEDIFF(QUARTER, 0, @Date), 0) | 同左 |
| 下季末日 | DATEADD(QUARTER, 2+DATEDIFF(QUARTER, 0, @Date), 0) - 1 | 同左 |
DAY(DATEADD(MONTH, DATEDIFF(MONTH, -1, @Date), -1)) -- 利用上年末日 + 2月 = 本年2月末日
DATEDIFF(DAY, DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date), 0), DATEADD(MONTH, 1+DATEDIFF(MONTH, 0, @Date), 0))
DATEDIFF(DAY, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, @Date), 0), DATEADD(QUARTER, 1+DATEDIFF(QUARTER, 0, @Date), 0))
DATEDIFF(DAY, DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0), DATEADD(YEAR, 1+DATEDIFF(YEAR, 0, @Date), 0))
-- 方法 1:本年天數
CASE DATEDIFF(DAY, DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0), DATEADD(YEAR, 1+DATEDIFF(YEAR, 0, @Date), 0))
WHEN 365 THEN '平年' ELSE '閏年' END
-- 方法 2:2月天數
CASE DAY(DATEADD(MONTH, 2, DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), -1)))
WHEN 28 THEN '平年' ELSE '閏年' END
DATEPART(DAYOFYEAR, @Date) -- 第 N 天
DATEPART(WEEK, @Date) -- 第 N 週 (依 DATEFIRST)
DATEPART(MONTH, @Date) -- 第 N 月
DATEPART(QUARTER, @Date) -- 第 N 季
-- 本月第一個週一 (1900-01-01 為週一)
DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEADD(DAY, 6-DATEPART(DAY, @Date), @Date)), 0)
-- 第 2 個週一:+7,第 1 個週二:+1,以此類推
0 = 1900-01-01 (週一)、-1 = 1899-12-31 (週日),避免字串日期格式問題CONVERT(VARCHAR, @Date, 112) 等字串操作效能差、易錯SET DATEFIRST 7 (美式週日首) 或 1 (歐式週一首),或用基準點法 (0/-1) 免受影響CREATE FUNCTION dbo.FirstDayOfMonth(@Date DATE) RETURNS DATE AS BEGIN RETURN DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date), 0) END,查詢中直接呼叫WHERE OrderDate >= dbo.FirstDayOfMonth(GETDATE()) AND OrderDate < dbo.FirstDayOfMonth(DATEADD(MONTH,1,GETDATE())) 可用索引DATE, TIME, DATETIME2, DATETIMEOFFSET 新型別,精度更高EOMONTH(@Date) 直接取月末日、DATEFROMPARTS 組合日期DATETIME 精度 3.33ms,新版 DATETIME2 100ns