需求:「已知 2004 年 11 月、星期一、第 4 週,求該日期 (2004-11-22)」。本文提供通用標量函數 RequestDate(@year, @month, @weekday, @week),支援任意年月、星期幾、第 N 週計算對應日期。
CREATE FUNCTION dbo.RequestDate
(
@year SMALLINT, -- 年 (如 2004)
@month TINYINT, -- 月 (1-12)
@weekday VARCHAR(6), -- 星期幾:'星期一'~'星期日'
@week TINYINT -- 第 N 週 (1-5)
)
RETURNS DATETIME
AS
BEGIN
DECLARE @firstDayOfMonth CHAR(10), @monthStr CHAR(2);
SET @monthStr = RIGHT('0' + CAST(@month AS VARCHAR(2)), 2);
SET @firstDayOfMonth = CAST(@year AS CHAR(4)) + '-' + @monthStr + '-01';
-- 該月 1 日在當年的週數
DECLARE @firstWeekOfYear INT = DATEPART(ww, @firstDayOfMonth);
-- 目標週在當年的週數 (假設跨年週歸屬当年)
DECLARE @targetWeekOfYear INT = @firstWeekOfYear + @week - 1;
-- 目標週第一天 (星期日) 的日期
DECLARE @weekStartDate DATETIME = DATEADD(ww, @targetWeekOfYear - 1, CAST(@year AS CHAR(4)) + '-01-01');
-- 星期對應數字 (SQL Server: 星期日=1 ... 星期六=7)
DECLARE @targetWeekdayNum TINYINT =
CASE @weekday
WHEN '星期日' THEN 1 WHEN '星期一' THEN 2 WHEN '星期二' THEN 3
WHEN '星期三' THEN 4 WHEN '星期四' THEN 5 WHEN '星期五' THEN 6
WHEN '星期六' THEN 7 ELSE 1 END;
-- 目標週第一天的實際星期數
DECLARE @weekStartWeekday TINYINT = DATEPART(dw, @weekStartDate);
-- 差異天數
DECLARE @diffDays INT = @targetWeekdayNum - @weekStartWeekday;
RETURN DATEADD(day, @diffDays, @weekStartDate);
END;
GO
SELECT dbo.RequestDate(2004, 11, '星期一', 4); -- 2004-11-22 00:00:00.000
SELECT dbo.RequestDate(2023, 10, '星期三', 2); -- 2023-10-11
SELECT dbo.RequestDate(2024, 2, '星期日', 1); -- 2024-02-04
| 情況 | 處理邏輯 |
|---|---|
| 第 5 週不存在 (月份不足 29 天) | 函數仍回傳計算日期 (可能落入下個月),呼叫端需自行驗證 MONTH(result) = @month |
| 跨年週 (1 月初屬前年最後一週) | DATEPART(ww) 依 SET DATEFIRST 定義,建議明確 SET DATEFIRST 7 (美式/中文習慣:週日為第一天) |
| @weekday 拼音/英文輸入 | 可擴充 CASE 分支支援 'Mon'、'Monday' 等 |