首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 依年、月、星期、第 N 週計算具體日期函數:RequestDate 完整實作

     編輯:關於SqlServer

需求:「已知 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

邊界情況處理

進階:直接用 DATEFROMPARTS + 邏輯 (SQL 2012+ 更簡潔)

CREATE FUNCTION dbo.RequestDate_v2
(
    @year INT, @month INT, @weekdayName VARCHAR(10), @week TINYINT
)
RETURNS DATE
AS
BEGIN
    DECLARE @firstDay DATE = DATEFROMPARTS(@year, @month, 1);
    DECLARE @firstWeekday INT = DATEPART(dw, @firstDay);  -- 1=Sun
    DECLARE @targetWeekday INT = CASE @weekdayName WHEN '星期一' THEN 2 ... END;
    DECLARE @offset INT = (@targetWeekday - @firstWeekday + 7) % 7;  -- 第一個目標星期幾的偏移
    DECLARE @firstTarget DATE = DATEADD(day, @offset, @firstDay);
    RETURN DATEADD(week, @week - 1, @firstTarget);
END;

新版語法更清晰、不依賴 ww 週數定義歧異,建議 SQL 2012+ 環境採用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
情況處理邏輯
第 5 週不存在 (月份不足 29 天)函數仍回傳計算日期 (可能落入下個月),呼叫端需自行驗證 MONTH(result) = @month
跨年週 (1 月初屬前年最後一週)DATEPART(ww) 依 SET DATEFIRST 定義,建議明確 SET DATEFIRST 7 (美式/中文習慣:週日為第一天)
@weekday 拼音/英文輸入可擴充 CASE 分支支援 'Mon'、'Monday' 等