取得某月天數的核心邏輯:**求下個月第一天,減一天,取 DAY 部分**。本文提供三種常見場景的標準寫法,並解析 DAY() 與 DATEPART(day, ...) 等價性。
DAY( DATEADD(month, 1, <目標月第一天>) - 1 )
DATEADD(month, 1, ...):推進到下個月第一天。- 1:退回上個月最後一天 (datetime 運算自動處理月份邊界)。DAY(...):擷取日期部分 → 即該月總天數。SELECT DAY(CAST('2008-03-01' AS DATETIME) - 1); -- 29 (2008 為閏年)
-- 或更直觀
SELECT DAY(DATEADD(month, 1, '2008-02-01') - 1);
SELECT DAY(DATEADD(month, 1, GETDATE()) - DAY(GETDATE()));
-- 邏輯: 今天 -> 加 1 月 -> 減去今天的日數 -> 得到本月最後一天 -> 取 DAY
**等價簡化** (SQL Server 2012+):
SELECT DAY(EOMONTH(GETDATE())); -- EOMONTH 直接回傳本月最後一天
SELECT DAY(GETDATE() - DAY(GETDATE()));
-- 邏輯: 今天 -> 減去今天的日數 -> 得到上月最後一天 -> 取 DAY
**等價簡化** (SQL Server 2012+):
SELECT DAY(EOMONTH(GETDATE(), -1));
| 函數 | 語法 | 回傳型別 | 備註 |
|---|---|---|---|
| DAY | DAY(date) | INT | DATEPART(day, date) 同義詞 |
| MONTH | MONTH(date) | INT | DATEPART(month, date) 同義詞 |
| YEAR | YEAR(date) | INT | DATEPART(year, date) 同義詞 |
| EOMONTH | EOMONTH(start_date [, month_offset]) | DATE | SQL 2012+,**首選**,可直接加減月份 |
DAY(EOMONTH(...)),**最簡潔、語意最清晰、效能最佳**。DAY(DATEADD(month, 1, ...) - 1) 模式,經過充分測試、無時區/語言相依性。SUBSTRING, CONVERT) 計算天數,效能差且易錯。DECLARE @Year INT = 2024;
WITH Months AS (
SELECT 1 AS M UNION ALL SELECT M+1 FROM Months WHERE M < 12
)
SELECT
M AS Month,
DAY(EOMONTH(DATEFROMPARTS(@Year, M, 1))) AS DaysInMonth
FROM Months
OPTION (MAXRECURSION 12);
掌握「下月 1 號減 1 天」通用邏輯,不再為閏年、大小月邊界條件煩惱。