SQL Server UDF for getting week of year, with first day of week argument

2.7k views Asked by At

I'm looking for a SQL Server UDF that will be equivalent to DATEPART(WEEK, @date), but will allow the caller to specify the first day of the week. Somewhat similar to MySql's WEEK function. E.g.:

CREATE FUNCTION Week (@date date, @firstdayofweek int)
RETURNS int
BEGIN
  -- return result would be the same as:
  --   SET DATEFIRST @firstdayofweek
  --   DATEPART(WEEK, @date)
END

My application does not have the opportunity to call SET DATEFIRST.

Examples:

SELECT Week('2013-08-28', 2) -- returns 35
SELECT Week('2013-08-28', 3) -- returns 36

The above results would always be the same, regardless of SQL Server's value for @@DATEFIRST.

3

There are 3 answers

0
Brad R On BEST ANSWER

I've found a couple of articles that helped me answer to derive an answer to this question:

  1. Deterministic scalar function to get week of year for a date

  2. http://sqlmag.com/t-sql/datetime-calculations-part-3

It may be possible to simplify this UDF, but it gives me exactly what I was looking for:

CREATE FUNCTION Week (@date DATETIME, @dateFirst INT)
RETURNS INT
BEGIN
  DECLARE @normalizedWeekOfYear INT = DATEDIFF(WEEK, DATEADD(YEAR, DATEDIFF(YEAR, 0, @date), 0), @date) + 1
  DECLARE @jan1DayOfWeek INT = DATEPART(WEEKDAY, DATEADD(YEAR, DATEDIFF(YEAR, 0, @date), 0) + @@DATEFIRST- 7) - 1
  DECLARE @dateDayOfWeek INT = DATEPART(WEEKDAY, DATEADD(DAY, @@DATEFIRST- 7, @date)) - 1

  RETURN @normalizedWeekOfYear + 
    CASE
      WHEN @jan1DayOfWeek < @dateFirst AND @dateDayOfWeek >= @dateFirst THEN 1
      WHEN @jan1DayOfWeek >= @dateFirst AND @dateDayOfWeek < @dateFirst THEN -1
      ELSE 0
    END
END
GO

Then, executing the following statements would return 35 and 36 respectively:

SELECT dbo.Week('2013-08-28', 2)
SELECT dbo.Week('2013-08-28', 3)
1
JG JIN On
/*
No matter how @@DATEFIRST is
return result as
weekdayName,weekdayNumber
Mo  1
Tu  2
Wn  3
Th  4
Fr  5
Sa  6
Su  7
*/

CREATE FUNCTION dbo.fnFixWeekday
(
    @currentDate date
)
RETURNS INT
AS
BEGIN
    -- get DATEFIRST setting
    DECLARE @ds int = @@DATEFIRST 
    -- get week day number under current DATEFIRST setting
    DECLARE @dow int = DATEPART(dw,@currentDate) 

    RETURN 1+(((@dow+@ds) % 7)+5) % 7

END
4
jellomonkey On

You could use something like this:

DATEPART(WEEK, DATEADD(DAY, 8 - @firstdayofweek, @date))

Instead of moving the first day of the week you are moving the actual date. Using this formula the first day of the week would be set using the same number values for days that MS SQL Server uses. (Sunday = 1, Saturday = 7)