2017-09-15 243 views
0

我在SQL中创建了一个函数,以便从类似“15W53”的格式中返回ISO Week中的正确日期。 “W”前的第一部分是年份编号,后半部分是周编号。返回的日期应该返回该日期的一周的开始。从SQL中的ISO Week获取日期

因此,例如,15W53应返回12-28-2015和16W01应返回01-04-2016。但是,如果我为以下示例运行此操作,那么从我所读取的关于ISO的一周中得出的结果不正确。

我是否创建了错误地解析日期的函数?

SET DATEFIRST 1; 
SELECT dbo.[GetDateFromISOweek]('15W52') AS Correct, '15W52' -- Returns: 2015-12-21 
SELECT dbo.[GetDateFromISOweek]('15W53') AS Correct, '15W53' -- Returns: 2015-12-28 
SELECT dbo.[GetDateFromISOweek]('16W01') AS Incorrect, '16W01'-- Returns: 2015-12-28 
SELECT dbo.[GetDateFromISOweek]('16W02') AS Incorrect, '16W02'-- Returns: 2016-01-04 
SELECT dbo.[GetDateFromISOweek]('16W03') AS Incorrect, '16W03'-- Returns: 2016-01-11 

功能:

CREATE FUNCTION [dbo].[GetDateFromISOweek] (@Input VARCHAR(10)) 
RETURNS DATETIME 
WITH EXECUTE AS CALLER 
AS 
BEGIN 
    DECLARE @YearNum CHAR(4) 
    DECLARE @WeekNum VARCHAR(2) 

    SET @YearNum = SUBSTRING(@Input,0,CHARINDEX('W',@Input,0)) 
    SET @WeekNum = SUBSTRING(@Input,CHARINDEX('W',@Input,0)+1,LEN(@Input)) 

    RETURN(DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + @YearNum) + (@WeekNum-1), 7)); 
END; 
+1

我的建议是任何时候你需要编写一个函数来计算一个日期,你应该考虑创建一个日期维度表。它会让你的生活变得更容易1000%。 https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/ – Shawn

+0

嘿肖恩,这是一个好主意!感谢您的链接! – InvaderZim

回答

1

更改-1你的回报来计算,如果一年中的第一个星期应考虑的第一个或没有(如果有超过3天)。 像这样

case when DATEDIFF (day , convert(datetime,'01/01/'+ @YearNum),@FirstDay)>=3 then 1 else 0 end 

完整的代码,包括第一个星期日,可改善,但工程...

CREATE FUNCTION [dbo].[GetDateFromISOweek] (@Input VARCHAR(10)) 
RETURNS DATETIME 
WITH EXECUTE AS CALLER 
AS 
BEGIN 
    DECLARE @YearNum CHAR(4) 
    DECLARE @WeekNum VARCHAR(2) 
    declare @FirstDay datetime 

    SET @YearNum = cast(SUBSTRING(@Input,0,CHARINDEX('W',@Input,0)) as int)+2000 
    SET @WeekNum = SUBSTRING(@Input,CHARINDEX('W',@Input,0)+1,LEN(@Input)) 
    set @FirstDay=DATEADD(DAY, (@@DATEFIRST - DATEPART(WEEKDAY, DATEADD(YEAR, @YearNum - 1900, 0)) + (8 - @@DATEFIRST) * 2) % 7, DATEADD(YEAR, @YearNum - 1900, 0))-1 

    RETURN(DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + @YearNum) + (@WeekNum-case when DATEDIFF (day , convert(datetime,'01/01/'+ @YearNum),@FirstDay)>=3 then 1 else 0 end), 7)); 
END; 
go 
SET DATEFIRST 1; 
SELECT dbo.[GetDateFromISOweek]('15W52'),'15W52' union 
SELECT dbo.[GetDateFromISOweek]('15W53'),'15W53' union 
SELECT dbo.[GetDateFromISOweek]('16W01'), '16W01' union 
SELECT dbo.[GetDateFromISOweek]('16W02'), '16W02' union 
SELECT dbo.[GetDateFromISOweek]('16W03'), '16W03' 

其结果将是

----------------------- ----- 
2015-12-21 00:00:00.000 15W52 
2015-12-28 00:00:00.000 15W53 
2016-01-04 00:00:00.000 16W01 
2016-01-11 00:00:00.000 16W02 
2016-01-18 00:00:00.000 16W03 
+0

太棒了!它像一个魅力! – InvaderZim