同一周 ⇔ 同年且同年周號相同。但跨年周(如 12/31 屬於下一年第一周)需特殊處理。
-- 參數:@dt1, @dt2 為 date/datetime 類型
-- 返回 1 表示同一周,0 表示不同周
CREATE FUNCTION dbo.IsSameWeek(@dt1 DATE, @dt2 DATE)
RETURNS BIT
AS
BEGIN
-- 設置週一為周首(SET DATEFIRST 1 對當前會話生效,建議顯式計算避免依賴會話設置)
-- 方法:以固定基準日期(如 1900-01-01 是週一)計算偏移
DECLARE @base DATE = '19000101'; -- Monday
-- 計算各自距離基準的周數(整除 7)
DECLARE @week1 INT = DATEDIFF(DAY, @base, @dt1) / 7;
DECLARE @week2 INT = DATEDIFF(DAY, @base, @dt2) / 7;
RETURN CASE WHEN @week1 = @week2 THEN 1 ELSE 0 END;
END
-- 需確保會話 DATEFIRST = 1(週一為首)
SET DATEFIRST 1; -- 僅影響當前連接
SELECT CASE
WHEN DATEPART(WEEK, @dt1) = DATEPART(WEEK, @dt2)
AND DATEPART(YEAR, @dt1) = DATEPART(YEAR, @dt2)
THEN 1 ELSE 0 END AS IsSameWeek;
-- 情況:@dt1=2023-12-31 (週日),@dt2=2024-01-01 (週一) → 實際同一周(ISO 8601 第 1 周)
-- DATEPART(WEEK) 可能判定為不同周,需額外邏輯
SELECT CASE
WHEN DATEPART(WEEK, @dt1) = DATEPART(WEEK, @dt2)
AND DATEPART(YEAR, @dt1) = DATEPART(YEAR, @dt2)
THEN 1
-- 跨年周修正:年末最後一天屬於下一年第一周
WHEN DATEPART(WEEK, @dt1) = DATEPART(WEEK, DATEFROMPARTS(YEAR(@dt1), 12, 31))
AND DATEPART(WEEKDAY, DATEFROMPARTS(YEAR(@dt1), 12, 31)) <> 1 -- 非週一
AND YEAR(@dt2) = YEAR(@dt1) + 1
AND DATEPART(WEEK, @dt2) = 1
THEN 1
ELSE 0 END;
-- 通用內聯表達式
WITH params AS (
SELECT @dt1 AS dt1, @dt2 AS dt2
),
weeks AS (
SELECT
dt,
-- ISO 週數:(日期 - 該年第一個週四) / 7 + 1
DATEPART(ISO_WEEK, dt) AS iso_week, -- SQL Server 2008+ 支持 ISO_WEEK
DATEPART(YEAR, dt) AS yr
FROM params
CROSS APPLY (VALUES (dt1), (dt2)) AS t(dt)
)
SELECT CASE WHEN MAX(iso_week) = MIN(iso_week) AND MAX(yr) = MIN(yr) THEN 1 ELSE 0 END
FROM weeks;
| 方法 | 依賴 DATEFIRST | 跨年周正確性 | 適用版本 |
|---|---|---|---|
| DATEDIFF 基準法 | 否 | 正確(固定基準) | 所有版本 |
| DATEPART(WEEK) | 是 | 需修正 | 所有版本 |
| DATEPART(ISO_WEEK) | 否 | 標準正確 | SQL Server 2008+ |
「固定基準日 + 整除 7」或「ISO_WEEK」是判斷同一周的工業級寫法,擺脫會話設置依賴,跨年周零 Bug。