64

In Microsoft SQL Server, I have a week number

(from DATEPART(wk, datecol)) 

But what I would like to do is turn this back into the date span for that week.

For example,

SELECT DATEPART(wk, GETDATE())

yields 10. I would like to derive 3/1/2009 and 3/7/2009 from this number.

Is this possible?

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
Jason
  • 985
  • 1
  • 6
  • 12
  • 1
    See also: http://stackoverflow.com/questions/1267126/how-do-you-get-the-week-start-date-and-week-end-date-from-week-number-in-sql – Aaron Hoffman Feb 22 '12 at 14:37

21 Answers21

45

Quassnoi's answer works, but kind of leaves you on the hook for cleaning up the dates if they are dates in the middle of the day (his start of week leaves you one day earlier than you need to be if you use a time in the middle of the day -- you can test using GETDATE()).

I've used something like this in the past:

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

A side benefit of this is that by using @@DATEFIRST you can handle nonstandard week starting days (the default is Sunday, but with SET @@DATEFIRST you can change this).

It seems crazy that simple date manipulation in SQL Server has to be this arcane, but there you go...

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
mwigdahl
  • 16,268
  • 7
  • 50
  • 64
  • Um, DATECOL is the user-defined column in the example. Quassnoi's code only relies on "DATEPART(weekday,", which is available on 2000. – jennykwan Mar 03 '09 at 20:35
  • 5
    NB. This does *not* work if you change the week starting day, as claimed. The default starting weekday is 7 (Sunday) and this code calculates assuming the current day is always <= 7. If you set the starting weekday to 1 (Monday), this code hits negative numbers and ends up showing you wrong dates from the week before. – TessellatingHeckler Feb 20 '14 at 17:57
  • 2
    NB. For similar reasons, I think it won't work at the start or end of a year either - saying week 1 began sometime in December of the previous year, or week 52 might end sometime in January the following year. – TessellatingHeckler Feb 20 '14 at 22:31
23

You can set @WeekNum and @YearNum to whatever you want - in this example they are derived from the @datecol variable, which is set to GETDATE() for purposes of illustration. Once you have those values- you can calculate the date range for a week by using the following:

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;
Josiah Nunemaker
  • 781
  • 10
  • 20
elindeblom
  • 231
  • 2
  • 2
  • Could you explain what the 6 and 5 are for in the DATEDIFF? – Ben Feb 18 '15 at 18:42
  • @BenAdler doing `select cast(0 as datetime)` returns `1900-01-01 00:00:00.000`, so 5 and 6 must be 5 and 6 days from jan 1, 1900 respectively. jan 7 is the first sunday of the year 1900. rest of calc is better shown than explained: `select datediff(wk, 6, '1/1/2015');` returns 5999 weeks since 1/7/1900 `select datepart(wk, '6/23/2015');` returns 26 weeks since 1/1/2015 `select dateadd(wk, 5999 + (26 - 1), 6);` returns: 2015-06-21 00:00:00.000, which is exactly 6024 weeks since the first sunday of year 1900, ergo also a sunday – ZagNut Jun 23 '15 at 21:23
  • 2
    The last two lines where exactly what we needed! Only changed the 5 and 6 because the weeks are starting on monday and ending on sunday here. 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 – Rob Jul 23 '15 at 07:57
11

To answer your question:

--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)))
Dave Newman
  • 1,018
  • 10
  • 15
Brad
  • 111
  • 1
  • 2
4

If your week starts from Monday (on 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
SeeR
  • 2,158
  • 1
  • 20
  • 35
3
SELECT DATECOL - DATEPART(weekday, DATECOL), DATECOL - DATEPART(weekday, DATECOL) + 7
Quassnoi
  • 413,100
  • 91
  • 616
  • 614
3

How about a function that jumps to the week before that week number and then steps through the next few days until the week number changes (max 7 steps), returning the new date?

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
Marc Ozin
  • 31
  • 2
  • 1
    Great! but i ´ve to edit set @tmpdate=dateadd(wk,@weekno-2,@tmpdate) – sebacipo Jan 09 '14 at 18:28
  • Sebacipo was right as the first day of Week 1 may be in December of the previous year. Also, the validation is incorrect if the last day in the year is week 1. Thanks for sharing though....this is perfect, with a few tweeks – Ian Oct 04 '16 at 08:46
2

I've taken elindeblom's solution and modified it - the use of strings (even if cast to dates) makes me nervous for the different formats of dates used around the world. This avoids that issue.

While not requested, I've also included time so the week ends 1 second before midnight:

    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] ;

Yes, I know I'm still casting but from a number. It "feels" safer to me.

This results in:

    start_of_week           end_of_week
    ----------------------- -----------------------
    2014-03-16 00:00:00.000 2014-03-22 23:59:59.000
Paul Sturm
  • 2,118
  • 1
  • 18
  • 23
2

Give it @Year and @Week, return first date of that 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')
markmolamhoi
  • 131
  • 1
  • 4
2

Another way to do it:

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

Explanation:

  • @week_number is computed based on the initial calendar date '1900-01-01'. Replace getdate() by whatever date you want.
  • @start_weekday is 0 if Monday. If Sunday, then declare it as -1
  • @end_weekday is 6 if next Sunday. If Saturday, then declare it as 5
  • Then dateadd function, will add the given number of weeks and the given number of days to the initial calendar date '1900-01-01'.
hd84335
  • 8,815
  • 5
  • 34
  • 45
  • Just a quick note to add to this, the start_weekday integer value of 0 is interpreted as a date (1900-01-01) when used in the DATEADD function. Similarly, the end_weekday integer value of 6 is interpreted as a date (1900-01-07) when used in the DATEADD function. The DATEADD function is applying a week offset to these base values. – ZenoArrow Jan 21 '22 at 17:39
1
dateadd(
  dd, 
  datepart(wk, @Date)*7, 
  convert(smalldatetime, convert(char,year(max(@Date)))+convert(char, '-01-01'))
)-1 
j0k
  • 22,600
  • 28
  • 79
  • 90
Charlie
  • 11
  • 1
1

Here you just have to pass year and week number.

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
NoNaMe
  • 6,020
  • 30
  • 82
  • 110
Ajay
  • 84
  • 6
1

I just incorporated the SELECT with a CASE statement (For my situation Monday marked the first day of the week, and didn't want to deal with the SET DATEFIRST command:

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
1

The most votes answer works fine except the 1st week and last week of year. When datecol value is '2009-01-01', the result will be 01/03/2009 and 12/28/2008.

My solution:

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;

This will display 01/01/2009 and 01/03/2009 for the 1st week, and display 03/01/2009 and 03/07/2009 for the 10th week.

I think this would be what you want exactly. You can replace the variables with their expressions as you wish.

Leo
  • 66
  • 4
1

This should work regardless of @@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
Steve Czetty
  • 6,147
  • 9
  • 39
  • 48
kunguito
  • 21
  • 4
1
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
DanB
  • 2,022
  • 1
  • 12
  • 24
0

Answer:

select  DateAdd(day,-DATEPart(DW,<Date>), <Date>) [FirstDayOfWeek] ,DateAdd(day,-DATEPart(DW,<Date>)+6, <Date>) [LastDayOfWeek]
FROM <TABLE>
Eduardo Briguenti Vieira
  • 4,351
  • 3
  • 37
  • 49
0

This works for me:

select 
    convert(varchar(50), dateadd(dd, - datepart(dw, DATECOL) + 1, DATECOL), 101),
    convert(varchar(50), dateadd(dd, - datepart(dw, DATECOL) + 7, DATECOL), 101)
Tomas Chabada
  • 2,869
  • 1
  • 17
  • 18
0
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'))
Brad
  • 15,361
  • 6
  • 36
  • 57
0

I didn't take the time to test out every answer on here, but nothing seems as simple and as efficient as this:

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
hurleystylee
  • 602
  • 1
  • 10
  • 18
0
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
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
0

A solution with:

  • Support for 1st and last week of the year
  • Support for monday or sunday as 1st day of the week
  • No string manipulation
SET DATEFIRST 1; -- Optionnal : if monday is your 1st day of the week

DECLARE @year INT = 2022;
DECLARE @week INT = 1;

SELECT [WeekStart] = CASE @week WHEN 1 THEN DATEADD(YEAR, @year - 1900, 0) ELSE DATEADD(DAY, 1 - DATEPART(WEEKDAY, DATEADD(WEEK, @week, DATEADD(YEAR, @year - 1900, 0))), DATEADD(WEEK, @week - 1, DATEADD(YEAR, @year - 1900, 0))) END
SELECT [WeekEnd] = CASE @week WHEN 53 THEN DATEADD(DAY, -1, DATEADD(YEAR, @year + 1 - 1900, 0)) ELSE DATEADD(DAY, -DATEPART(WEEKDAY, DATEADD(WEEK, @week, DATEADD(YEAR, @year - 1900, 0))), DATEADD(WEEK, @week, DATEADD(YEAR, @year - 1900, 0))) END

e.g. with year 2022, week 1 :

enter image description here

Tested with dates from 2023 to 2035.

Marcus Gambit
  • 180
  • 1
  • 9