【问题标题】:Get dates from a week number in T-SQL从 T-SQL 中的周数获取日期
【发布时间】:2010-10-11 02:31:15
【问题描述】:

在 Microsoft SQL Server 中,我有一个星期数

(from DATEPART(wk, datecol)) 

但我想做的是把它变成那一周的日期跨度。

例如,

SELECT DATEPART(wk, GETDATE())

yields 10。我想从这个数字派生出3/1/20093/7/2009

这可能吗?

【问题讨论】:

标签: sql-server tsql date


【解决方案1】:
SELECT DATECOL - DATEPART(weekday, DATECOL), DATECOL - DATEPART(weekday, DATECOL) + 7

【讨论】:

    【解决方案2】:

    Quassnoi 的回答很有效,但是如果日期是在一天中的日期,那会让你不得不清理日期(如果你使用时间,他的一周开始会让你比你需要的时间早一天在中午 -- 您可以使用 GETDATE()) 进行测试。

    我过去用过这样的东西:

    SELECT 
       CONVERT(varchar(50), (DATEADD(dd, @@DATEFIRST - DATEPART(dw, DATECOL), DATECOL)), 101),
       CONVERT(varchar(50), (DATEADD(dd, @@DATEFIRST - DATEPART(dw, DATECOL) - 6, DATECOL)), 101)
    

    这样做的一个附带好处是,通过使用@@DATEFIRST,您可以处理非标准的星期开始日期(默认为星期日,但使用 SET @@DATEFIRST 您可以更改此设置)。

    SQL Server 中的简单日期操作必须如此神秘,这似乎很疯狂,但是你去...

    【讨论】:

    • 嗯,DATECOL是示例中的用户自定义列。 Quassnoi 的代码仅依赖于“DATEPART(weekday,”),它在 2000 年可用。
    • 注意。如声称的那样,如果您更改一周的开始日期,这不起作用。默认开始工作日为 7(星期日),此代码计算假设当前日期始终
    • 注意。出于类似的原因,我认为它也不会在一年的开始或结束时起作用 - 说第 1 周开始于去年 12 月的某个时间,或者第 52 周可能在次年 1 月的某个时间结束。
    【解决方案3】:

    您可以将@WeekNum 和@YearNum 设置为您想要的任何值——在此示例中,它们派生自@datecol 变量,该变量设置为GETDATE() 以进行说明。获得这些值后,您可以使用以下方法计算一周的日期范围:

    DECLARE @datecol datetime = GETDATE();
    DECLARE @WeekNum INT
          , @YearNum char(4);
    
    SELECT @WeekNum = DATEPART(WK, @datecol)
         , @YearNum = CAST(DATEPART(YY, @datecol) AS CHAR(4));
    
    -- once you have the @WeekNum and @YearNum set, the following calculates the date range.
    SELECT DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + @YearNum) + (@WeekNum-1), 6) AS StartOfWeek;
    SELECT DATEADD(wk, DATEDIFF(wk, 5, '1/1/' + @YearNum) + (@WeekNum-1), 5) AS EndOfWeek;
    

    【讨论】:

    • 您能解释一下 6 和 5 在 DATEDIFF 中的用途吗?
    • @BenAdler 执行 select cast(0 as datetime) 返回 1900-01-01 00:00:00.000,因此 5 和 6 必须分别是 1900 年 1 月 1 日起的 5 天和 6 天。 1 月 7 日是 1900 年的第一个星期日。计算的其余部分显示得比解释要好:select datediff(wk, 6, '1/1/2015'); 自 1900 年 1 月 7 日起返回 5999 周 select datepart(wk, '6/23/2015'); 自 2015 年 1 月 1 日起返回 26 周 select dateadd(wk, 5999 + (26 - 1), 6); 返回:2015 年-06-21 00:00:00.000,距离 1900 年的第一个星期日正好是 6024 周,因此也是一个星期日
    • 最后两行正是我们需要的!只更改了 5 和 6,因为这里的星期从星期一开始,到星期日结束。 DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + CAST(pr.Jaar as nvarchar)) + (pr.Week-1), 7) AS StartOfWeek, DATEADD(wk, DATEDIFF(wk, 5, '1/1/' + CAST(pr.Jaar as nvarchar)) + (pr.Week-1), 6) AS EndOfWeek
    【解决方案4】:
    SELECT DATEADD(week, @weekNumber - 1, DATEADD(DAY, @@datefirst - DATEPART(weekday, CAST(YEAR(GETDATE()) AS VARCHAR) + '-01-01') - 6, CAST(YEAR(GETDATE()) AS VARCHAR) + '-01-01'))
    

    【讨论】:

      【解决方案5】:

      无论@@DATEFIRST如何,这都应该有效

      ALTER FUNCTION dbo.DEV_VW_WeekSerial
          (@YearNum int,
          @WeekNum int,
          @DayNum int)
          RETURNS Date AS
      
          BEGIN
      
              DECLARE @FirstDayYear As Date;
      
              SET @FirstDayYear='01/01/' + CAST(@YearNum As varchar)
      
              RETURN dateadd(d,(@DayNum-datepart(weekday,@FirstDayYear)),dateadd(week, @WeekNum-1,@FirstDayYear))
      
          END
      

      【讨论】:

        【解决方案6】:
        DECLARE @dayval int,
         @monthval int,
         @yearval int
        
        SET @dayval = 1
        SET @monthval = 1
        SET @yearval = 2011
        
        
        DECLARE @dtDateSerial datetime
        
                SET @dtDateSerial = DATEADD(day, @dayval-1,
                                        DATEADD(month, @monthval-1,
                                            DATEADD(year, @yearval-1900, 0)
                                        )
                                    )
        
        DECLARE @weekno int
        SET @weekno = 53
        
        
        DECLARE @weekstart datetime
        SET @weekstart = dateadd(day, 7 * (@weekno -1) - datepart (dw, @dtDateSerial), @dtDateSerial)
        
        DECLARE @weekend datetime
        SET @weekend = dateadd(day, 6, @weekstart)
        
        SELECT @weekstart, @weekend
        

        【讨论】:

          【解决方案7】:

          如果有一个函数跳到该周数之前的一周,然后逐步执行接下来的几天,直到周数发生变化(最多 7 步),然后返回新日期?

          CREATE FUNCTION dbo.fnGetDateFromWeekNo
          (@weekNo int , @yearNo  int)
          RETURNS smalldatetime
          AS
          BEGIN 
          
          DECLARE @tmpDate smalldatetime
          
          
          set @tmpdate= cast(cast (@yearNo as varchar) + '-01-01' as smalldatetime)
          -- jump forward x-1 weeks to save counting through the whole year 
          set @tmpdate=dateadd(wk,@weekno-1,@tmpdate)
          
          -- make sure weekno is not out of range
          if @WeekNo <= datepart(wk,cast(cast (@yearNo as varchar) + '-12-31' as smalldatetime))
          BEGIN
              WHILE (datepart(wk,@tmpdate)<@WeekNo)
              BEGIN
                  set @tmpdate=dateadd(dd,1,@tmpdate)
              END
          END
          ELSE
          BEGIN
              -- invalid weeknumber given
              set @tmpdate=null
          END
          
          
          RETURN @tmpDate
          
          END
          

          【讨论】:

          • 太棒了!但我必须编辑设置 @tmpdate=dateadd(wk,@weekno-2,@tmpdate)
          • Sebacipo 是对的,因为第 1 周的第一天可能在前一年的 12 月。此外,如果一年中的最后一天是第 1 周,则验证不正确。尽管如此,谢谢分享....这是完美的,有几个 tweeks
          【解决方案8】:
          dateadd(
            dd, 
            datepart(wk, @Date)*7, 
            convert(smalldatetime, convert(char,year(max(@Date)))+convert(char, '-01-01'))
          )-1 
          

          【讨论】:

            【解决方案9】:

            在这里你只需要传递年份和周数。

            DECLARE @Year VARCHAR(4)
            
            SET @Year= '2012'
            
            DECLARE @FirstDate DATETIME
            
            SET @FirstDate = (SELECT DATEADD(dd,1,(SELECT DATEADD(wk,DATEPART(wk,GETDATE())-1,Convert(DAteTime,'01-01-' + @Year))))
                             )
            DECLARE @LastDate DATETIME
            
            SET @LastDate =(SELECT DATEADD(dd,4,@FirstDate))
            
            SELECT @FirstDate
                   ,@LastDate
            

            【讨论】:

              【解决方案10】:

              回答你的问题:

              --CHANGE A WEEK NUMBER BACK INTO A DATE FOR THE FIRST DATE OF THE WEEK
              DECLARE @TaskWeek INT = 17
              DECLARE @TaskYear INT = 2013
              
              SELECT DATEADD(WEEK, @TaskWeek - 1,DATEADD(dd, 1 - DATEPART(dw, '1/1/' + CONVERT(VARCHAR(4),@TaskYear)), '1/1/' + CONVERT(VARCHAR(4),@TaskYear)))
              

              【讨论】:

                【解决方案11】:

                如果您的一周从星期一开始(在 SQL Server 2008 上)

                select datecol,
                  DATEPART(ISOWK, datecol) as week,
                  ((DATEPART(dw, datecol)+5)%7)+1 as weekday,
                  (DATEADD(dd, -((DATEPART(dw, datecol)+5)%7), datecol)) as Monday,
                  (DATEADD(dd, -((DATEPART(dw, datecol)+5)%7)+6, datecol)) as Sunday
                

                【讨论】:

                  【解决方案12】:

                  答案:

                  select  DateAdd(day,-DATEPart(DW,<Date>), <Date>) [FirstDayOfWeek] ,DateAdd(day,-DATEPart(DW,<Date>)+6, <Date>) [LastDayOfWeek]
                  FROM <TABLE>
                  

                  【讨论】:

                    【解决方案13】:

                    我采用了 elindeblom 的解决方案并对其进行了修改 - 字符串的使用(即使转换为日期)让我对世界各地使用的不同日期格式感到紧张。这避免了这个问题。

                    虽然没有要求,但我还包括时间,因此一周在午夜前 1 秒结束:

                        DECLARE @WeekNum INT = 12,
                            @YearNum INT = 2014 ;
                    
                        SELECT  DATEADD(wk,
                                        DATEDIFF(wk, 6,
                                                 CAST(RTRIM(@YearNum * 10000 + 1 * 100 + 1) AS DATETIME))
                                        + ( @WeekNum - 1 ), 6) AS [start_of_week],
                                DATEADD(second, -1,
                                        DATEADD(day,
                                                DATEDIFF(day, 0,
                                                         DATEADD(wk,
                                                                 DATEDIFF(wk, 5,
                                                                          CAST(RTRIM(@YearNum * 10000
                                                                                     + 1 * 100 + 1) AS DATETIME))
                                                                 + ( @WeekNum + -1 ), 5)) + 1, 0)) AS [end_of_week] ;
                    

                    是的,我知道我仍在投射,但来自一个号码。它对我来说“感觉”更安全。

                    这会导致:

                        start_of_week           end_of_week
                        ----------------------- -----------------------
                        2014-03-16 00:00:00.000 2014-03-22 23:59:59.000
                    

                    【讨论】:

                      【解决方案14】:

                      给它@Year 和@Week, 返回该周的第一个日期。

                      Declare @Year   int
                      ,@Week int
                      ,@YearText varchar(4)
                      
                      set @Year = 2009
                      set @Week = 10
                      
                      set @YearText = @Year
                      
                      print dateadd(day
                                   ,1 - datepart(dw, @YearText + '-01-01')
                                      + (@Week-1) * 7
                                   ,@YearText + '-01-01')
                      

                      【讨论】:

                        【解决方案15】:

                        我刚刚将 SELECT 与 CASE 语句合并(对于我的情况,星期一标记为一周的第一天,并且不想处理 SET DATEFIRST 命令:

                        CASE DATEPART(dw,<YourDateTimeField>)
                           WHEN 1 THEN CONVERT(char(10), DATEADD(DD, -6, <YourDateTimeField>),126) +  ' to ' + CONVERT(char(10), <YourDateTimeField>,126)
                           WHEN 2 THEN CONVERT(char(10), <YourDateTimeField>,126) +  ' to ' + CONVERT(char(10), DATEADD(DD, 6, <YourDateTimeField>),126)
                           WHEN 3 THEN CONVERT(char(10), DATEADD(DD, -1, <YourDateTimeField>),126) +  ' to ' + CONVERT(char(10), DATEADD(DD, 5, <YourDateTimeField>),126)
                           WHEN 4 THEN CONVERT(char(10), DATEADD(DD, -2, <YourDateTimeField>),126) +  ' to ' + CONVERT(char(10), DATEADD(DD, 4, <YourDateTimeField>),126)
                           WHEN 5 THEN CONVERT(char(10), DATEADD(DD, -3, <YourDateTimeField>),126) +  ' to ' + CONVERT(char(10), DATEADD(DD, 3, <YourDateTimeField>),126)
                           WHEN 6 THEN CONVERT(char(10), DATEADD(DD, -4, <YourDateTimeField>),126) +  ' to ' + CONVERT(char(10), DATEADD(DD, 2, <YourDateTimeField>),126)
                           WHEN 7 THEN CONVERT(char(10), DATEADD(DD, -5, <YourDateTimeField>),126) +  ' to ' + CONVERT(char(10), DATEADD(DD, 1, <YourDateTimeField>),126)
                           ELSE 'UNK'
                        END AS Week_Range
                        

                        【讨论】:

                          【解决方案16】:

                          这对我有用:

                          select 
                              convert(varchar(50), dateadd(dd, - datepart(dw, DATECOL) + 1, DATECOL), 101),
                              convert(varchar(50), dateadd(dd, - datepart(dw, DATECOL) + 7, DATECOL), 101)
                          

                          【讨论】:

                            【解决方案17】:

                            我没有花时间在这里测试每个答案,但似乎没有什么比这更简单有效:

                            DECLARE @WeekNum int
                            DECLARE @YearNum char(4)
                            
                            SELECT DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + @YearNum) + (@WeekNum-1), 6) AS StartOfWeek
                            
                            SELECT DATEADD(wk, DATEDIFF(wk, 5, '1/1/' + @YearNum) + (@WeekNum-1), 5) AS EndOfWeek
                            

                            【讨论】:

                              【解决方案18】:

                              除了一年中的第一周和最后一周之外,得票最多的答案可以正常工作。当 datecol 值为 '2009-01-01' 时,结果将是 01/03/200912/28/ 2008 年

                              我的解决方案:

                              DECLARE @Date date = '2009-03-01', @WeekNum int, @StartDate date;
                              SELECT @WeekNum = DATEPART(WEEK, @Date);
                              SELECT @StartDate = DATEADD(DAY, -(DATEPART(WEEKDAY, DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0)) + 6), DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0));
                              SELECT CONVERT(nvarchar, CASE WHEN @WeekNum = 1 THEN CAST(DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0) AS date) ELSE DATEADD(DAY, 7 * @WeekNum, @StartDate) END, 101) AS StartOfWeek
                                    ,CONVERT(nvarchar, CASE WHEN @WeekNum = DATEPART(WEEK, DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date) + 1, 0))) THEN DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date) + 1, 0)) ELSE DATEADD(DAY, 7 * @WeekNum + 6, @StartDate) END, 101) AS EndOfWeek;
                              

                              这将在第一周显示 01/01/200901/03/2009,并显示 03/01/200903/07/2009 第 10 周。

                              我认为这正是您想要的。您可以根据需要将变量替换为表达式。

                              【讨论】:

                                【解决方案19】:
                                declare @IntWeek as varchar(20)
                                SET @IntWeek = '201820'
                                
                                SELECT 
                                    DATEADD(wk, DATEDIFF(wk, @@DATEFIRST, LEFT(@IntWeek,4) + '-01-01') +
                                    (cast(RIGHT(@IntWeek, 2) as int) -1), @@DATEFIRST) AS StartOfWeek
                                

                                【讨论】:

                                  【解决方案20】:

                                  另一种方法:

                                  declare @week_number int;
                                  declare @start_weekday int = 0 -- Monday
                                  declare @end_weekday int = 6 -- next Sunday
                                  
                                  select @week_number = datediff(week, 0, getdate())
                                  
                                  select 
                                      dateadd(week, @week_number, @start_weekday) as WEEK_FIRST_DAY, 
                                      dateadd(week, @week_number, @end_weekday) as WEEK_LAST_DAY
                                  

                                  解释:

                                  • @week_number 是根据初始日历日期“1900-01-01”计算得出的。用你想要的任何日期替换 getdate()
                                  • @start_weekday 如果是星期一,则为 0。如果是星期日,则将其声明为 -1
                                  • @end_weekday 是 6 如果下周日。如果是星期六,则将其声明为 5
                                  • 然后dateadd 函数,会将给定的周数和给定的天数添加到初始日历日期“1900-01-01”。

                                  【讨论】:

                                  • 只是一个快速说明,当在 DATEADD 函数中使用时,start_weekday 整数值 0 被解释为日期 (1900-01-01)。同样,当在 DATEADD 函数中使用时,end_weekday 整数值 6 被解释为日期 (1900-01-07)。 DATEADD 函数正在对这些基值应用一周偏移量。
                                  猜你喜欢
                                  • 2011-01-20
                                  • 2018-02-25
                                  • 2013-03-04
                                  • 2015-05-19
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 2020-12-14
                                  • 1970-01-01
                                  相关资源
                                  最近更新 更多