Get day of week in SQL Server 2005/2008 - sql

If I have a date 01/01/2009, I want to find out what day it was e.g. Monday, Tuesday, etc...
Is there a built-in function for this in SQL Server 2005/2008? Or do I need to use an auxiliary table?

Use DATENAME or DATEPART:
SELECT DATENAME(dw,GETDATE()) -- Friday
SELECT DATEPART(dw,GETDATE()) -- 6

Even though SQLMenace's answer has been accepted, there is one important SET option you should be aware of
SET DATEFIRST
DATENAME will return correct date name but not the same DATEPART value if the first day of week has been changed as illustrated below.
declare #DefaultDateFirst int
set #DefaultDateFirst = ##datefirst
--; 7 First day of week is "Sunday" by default
select [#DefaultDateFirst] = #DefaultDateFirst
set datefirst #DefaultDateFirst
select datename(dw,getdate()) -- Saturday
select datepart(dw,getdate()) -- 7
--; Set the first day of week to * TUESDAY *
--; (some people start their week on Tuesdays...)
set datefirst 2
select datename(dw,getdate()) -- Saturday
--; Returns 5 because Saturday is the 5th day since Tuesday.
--; Tue 1, Wed 2, Th 3, Fri 4, Sat 5
select datepart(dw,getdate()) -- 5 <-- It's not 7!
set datefirst #DefaultDateFirst

SELECT CASE DATEPART(WEEKDAY,GETDATE())
WHEN 1 THEN 'SUNDAY'
WHEN 2 THEN 'MONDAY'
WHEN 3 THEN 'TUESDAY'
WHEN 4 THEN 'WEDNESDAY'
WHEN 5 THEN 'THURSDAY'
WHEN 6 THEN 'FRIDAY'
WHEN 7 THEN 'SATURDAY'
END

EUROPE:
declare #d datetime;
set #d=getdate();
set #dow=((datepart(dw,#d) + ##DATEFIRST-2) % 7+1);

To get a deterministic value for the day of week for a given date you could use a combination of DATEPART() and ##datefirst. Otherwise your dependent on the settings on the server.
Check out the following site for a better solution:
MS SQL: Day of Week
The day of week will then be in the range 0 to 6, where 0 is Sunday, 1 is Monday, etc. Then you can use a simple case statement to return the correct weekday name.

With SQL Server 2012 and onward you can use the FORMAT function
SELECT FORMAT(GETDATE(), 'dddd')

You can use DATEPART(dw, GETDATE()) but be aware that the result will rely on SQL server setting ##DATEFIRST value which is the first day of week setting (In Europe default value 7 which is Sunday).
If you want to change the first day of week to another value, you could use SET DATEFIRST but this may affect everywhere in your query session which you do not want.
Alternative way is to explicitly specify the first day of week value as parameter and avoid depending on ##DATEFIRST setting. You can use the following formula to achieve that when need it:
(DATEPART(dw, GETDATE()) + ##DATEFIRST + 6 - #WeekStartDay) % 7 + 1
where #WeekStartDay is the first day of the week you want for your system (from 1 to 7 which means from Monday to Sunday).
I have wrapped it into below function so we can reuse it easily:
CREATE FUNCTION [dbo].[GetDayInWeek](#InputDateTime DATETIME, #WeekStartDay INT)
RETURNS INT
AS
BEGIN
--Note: #WeekStartDay is number from [1 - 7] which is from Monday to Sunday
RETURN (DATEPART(dw, #InputDateTime) + ##DATEFIRST + 6 - #WeekStartDay) % 7 + 1
END
Example usage:
GetDayInWeek('2019-02-04 00:00:00', 1)
It is equivalent to following (but independent to SQL server DATEFIRST setting):
SET DATEFIRST 1
DATEPART(dw, '2019-02-04 00:00:00')

this is a working copy of my code check it, how to retrive day name from date in sql
CREATE Procedure [dbo].[proc_GetProjectDeploymentTimeSheetData]
#FromDate date,
#ToDate date
As
Begin
select p.ProjectName + ' ( ' + st.Time +' '+'-'+' '+et.Time +' )' as ProjectDeatils,
datename(dw,pts.StartDate) as 'Day'
from
ProjectTimeSheet pts
join Projects p on pts.ProjectID=p.ID
join Timing st on pts.StartTimingId=st.Id
join Timing et on pts.EndTimingId=et.Id
where pts.StartDate >= #FromDate
and pts.StartDate <= #ToDate
END

If you don't want to depend on ##DATEFIRST or use DATEPART(weekday, DateColumn), just calculate the day of the week yourself.
For Monday based weeks (Europe) simplest is:
SELECT DATEDIFF(day, '17530101', DateColumn) % 7 + 1 AS MondayBasedDay
For Sunday based weeks (America) use:
SELECT DATEDIFF(day, '17530107', DateColumn) % 7 + 1 AS SundayBasedDay
This return the weekday number (1 to 7) ever since January 1st respectively 7th, 1753.

In addition all with above answers, dw stands for Week Day
SELECT DATENAME(WEEKDAY,GETDATE()) AS WeekDay
or
SELECT DATENAME(W,GETDATE()) AS WeekDay

You may find this version useful for returning a shortened weekday name in one line.
-- Test DATA
select ##datefirst
create table #test (datum datetime)
insert #test values ('2013-01-01')
insert #test values ('2013-01-02')
insert #test values ('2013-01-03')
insert #test values ('2013-01-04')
insert #test values ('2013-01-05')
insert #test values ('2013-01-06')
insert #test values ('2013-01-07')
insert #test values ('2013-01-08')
-- Test DATA
select Substring('Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun,Mon,Tue,Wed,Thu,Fri,Sat',
(DATEPART(WEEKDAY,datum)+##datefirst-1)*4+1,3),Datum
from #test

Related

Datepart week start Monday used in a view

I am trying to use the DATEPART function in my SELECT query that constructs a view.
The aim of the DATEPART is to return the weeknumber of a date passed to it. I require the start of the week to be a Monday and the default, which in my case is a Sunday.
I am not able to use Set DATEFIRST 1 since I want to use the Datepart in a view.
eg. Lets use the date '2021-01-31' as [Date]
DATEPART(WEEK,DATE) --returns week 6 with ##DATEFIRST = 7
DATEPART(WEEK,DATE) --returns week 5 with ##DATEFIRST = 1
All suggestions would highly be appreciated.
I can offer such a solution:
declare
#DATE date='2021-01-31'
select DATEPART(WEEK,#DATE) --returns week 6 with ##DATEFIRST = 7
,DATEPART(WEEK,case when datepart(dw, #DATE)=1 then dateadd(dd, -1, #DATE) else #DATE end) --returns week 5 with ##DATEFIRST = 1

SQL Server: change first day of week to Sunday using DATEPART with ISOWK parameter

I need to get week numbers for some set of dates. For example, for Jan 2016 it should be something like:
[Week Number]
53 <--- for dates from Jan 1 to Jan 2
1 <--- for dates from Jan 3 to Jan 9
2 <--- for dates from Jan 10 to Jan 16
... <--- etc.
As you see, week should start from Sunday. I've used following function to set start day:
SET DATEFIRST 7
And this one to get week number:
DATEPART(ISOWK, SOME_DATE)
But I've noticed that DATEFIRST doesn't affect results when ISOWK being used - week always starts from Monday.
So, what am I doing wrong? Thank you!
UPD:
I've made a function, seems it works good:
CREATE FUNCTION [dbo].[GetWeekNumber]
(
#date as DATETIME,
#offset as INT
)
RETURNS NVARCHAR(100)
BEGIN
DECLARE #weekNumber as int
DECLARE #year as int
SET #date = DATEADD(MINUTE, #offset, #date)
SET #year = DATEPART(year, DATEADD(DAY, 1 - DATEPART(WEEKDAY, #date), CAST(#date AS DATE)))
IF ##DATEFIRST = 7
BEGIN
SET #date = DATEADD(day, 1, #date)
END
SET #weekNumber = DATEPART(ISO_WEEK, #date)
RETURN concat(#year, ', Week ', right('0' + convert(nvarchar, #weekNumber), 2))
END
You need to pass the date and timezone offset (in minutes). And SET DATEFIRST #startDay before executing this function (1 - Monday, 7 - Sunday). Example:
DECLARE #date as DATETIME
SET #date = '2016-01-03 12:00'
SET DATEFIRST 1
SELECT dbo.GetWeekNumber(#date, 0) -- 2015, Week 53
SET DATEFIRST 7
SELECT dbo.GetWeekNumber(#date, 0) -- 2016, Week 01
This is by design. According to MSDN:
ISO 8601 includes the ISO week-date system, a numbering system for
weeks. Each week is associated with the year in which Thursday occurs.
For example, week 1 of 2004 (2004W01) ran from Monday 29 December 2003
to Sunday, 4 January 2004.
So ISOWK is always based on Thursday, and is not affected by DATEFIRST.
To get the results you want, just use WEEK instead of ISOWK.
UPDATE: Also from MSDN:
January 1 of any year defines the starting number for the week
datepart, for example: DATEPART (wk, 'Jan 1, xxxx') = 1, where xxxx is
any year.
The only way to get Week #1 to be Jan 3-9 is to use math. Subtract one from the DATEPART(wk...) value, and if the result is 0, make it 53 (or simply use DATEADD on your date to subtract a week). There is no simpler way, as by design, the first week of any year will be the week that contains Jan 1.

Get date of every second Tuesday of a month

Is there a way to find out the date of every second Tuesday of a month using T-SQL syntax?
E.g. in March it is the 12th, in April it's the 9th.
This is how you can find all 'second tuesdays' in 2013.
select
dateadd(day, 8, datediff(day, 1, dateadd(month, n, '2013-01-07')) / 7 * 7) date
from
(values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)) t(n)
Without knowing what the actual required inputs and outputs are, all I can give you at the moment is a predicate for identifying a date as the second tuesday of its month:
DATEPART(day,#Date) between 8 and 14 and --Find the second one in the month
DATEPART(weekday,#Date) = DATEPART(weekday,'20130319') --Make sure its a Tuesday
(I use a fixed, known Tuesday, so as to avoid having to know what DATEFIRST settings are in effect when the query is run)
This finds the appropriate Tuesday for the current month, but obviously #Date could be set to any date of interest:
declare #Date datetime
set #Date = CURRENT_TIMESTAMP
;with Numbers as (select n from (values (0),(1),(2),(3),(4),(5),(6)) t(n)),
PotentialDates as (select DATEADD(day,n,DATEADD(month,DATEDIFF(month,'20010101',#Date),'20010108')) as Date
from Numbers
)
select * from PotentialDates where DATEPART(weekday,Date) = DATEPART(weekday,'20130319')
(And, hopefully also obviously, the query could be part of a larger query, where #Date was instead a column value, and so this can form part of a set-based approach to the entire piece of work)
Previous answer does not work for months starting on Sunday ( it points to the second Sunday instead).
SELECT #dt AS input_date,
DATEADD(mm, DATEDIFF(mm, 0, #dt), 0) --truncate date to month start
-- DATEPART(#month_start) returns month start's weekday, with Sunday starting 1;
-- Since Sunday starts at 1, we need to perform proper adjustment - move date 6 days forward (7 week days - 1 for sunday) forward and find its datepart, which will be 7
-- Result: month starting sunday, datepart returns 7; month starting Mon we return 1 (datepart of Mon + 6 days = Sunday, which is 1), month starting tue, we return 2
-- Effectivelly, datepart offset will always point last Sunday of previous month
- DATEPART(dw,
6
+ DATEADD(mm,datediff(mm,0,#dt),0) --truncate date to month start
)
-- Since we found last Sunday of previous month, we need to add 7
+ 7 AS CORRECT,
dateadd(mm,datediff(mm,'',#dt),'') - datepart(dw,dateadd(mm,datediff(mm,'',#dt),'')+0)+ 8 AS sometimes_correct
Image that shows shows correct answer relative to the answer by Pravin Pandit:
We can extend this rationale for finding first Tue of the month and create a function that does that, so for any input date, it will find 1st Tue of the month in question:
ALTER FUNCTION dbo.f_time_floor_1st_tue(#date DATETIME2(3))
RETURNS DATETIME
AS
BEGIN
RETURN
DATEADD(mm, DATEDIFF(mm, 0, #date), 0) --truncate date to month start
-- DATEPART(#month_start) returns month start's weekday, with Sunday starting 1;
-- Since Sunday starts at 1, we need to perform proper adjustment - move date 6 days forward (7 week days - 1 for sunday) forward and find its datepart, which will be 7
-- Result: month starting sunday, datepart returns 7; month starting Mon we return 1 (datepart of Mon + 6 days = Sunday, which is 1), month starting tue, we return 2
-- Effectivelly, datepart offset will always point last Sunday of previous month
-- Extending this logic for finding first Tuesday, Tuesday should always return 7 we need to move Tue datepart (3) by 4 ( which is 7 days in the week minus 3
- DATEPART(dw,
4 -- 4 is adjustment so that DATEPART returns 7 for all months starting Tue
+ DATEADD(mm,datediff(mm,0,#date),0) --truncate date to month start
)
-- Since we found last weekday of previous month, we need to add 7
+ 7
;
END;
GO
This code will give you every 1st and 3rd Sunday of the month.
declare #dt datetime
select #dt = '12/01/2014'
select dateadd(mm,datediff(mm,'',#dt),'') - datepart(dw,dateadd(mm,datediff(mm,'',#dt),'')+0)+ 8
select dateadd(mm,datediff(mm,'',#dt),'') - datepart(dw,dateadd(mm,datediff(mm,'',#dt),'')+0)+ 22
This will give you current month's Patch Tuesday
Declare #Date DATETIME = Getdate()
--Set #Date = DAtefromParts(2022,01,01) -- for testing
Declare #PT DATETIME
Declare #WeekDay DATETIME
Declare #CM varchar(30)
Declare #FD DATETIME = DAtefromParts(DATEPART(yyyy,#date), DATEPART(mm,#date),01) --FirstDayof the month
print #FD
SET #WeekDay = DATEPART(WEEKDAY,#FD) --No of WeekDay
if #WeekDay =1
Begin
Set #PT = DateAdd(D,9,#FD)
end
else if #WeekDay =2
Begin
Set #PT = DateAdd(D,8,#FD)
end
else if #WeekDay =3
Begin
Set #PT = DateAdd(D,7,#FD)
end
else if #WeekDay =4
Begin
Set #PT = DateAdd(D,13,#FD)
end
else if #WeekDay =5
Begin
Set #PT = DateAdd(D,12,#FD)
end
else if #WeekDay =6
Begin
Set #PT = DateAdd(D,11,#FD)
end
else if #WeekDay =7
Begin
Set #PT = DateAdd(D,10,#FD)
End
Print #PT

For Mondays I need to set default date to previous Friday for App?

When a Report is run on a Monday it needs to set the default date to Friday ? Also 4 other conditions looking at the requirments. How to do this in an sql statement is the question.
So in pseudo code,
If today's date is Monday then set default date to Friday with full date format.
If today's date is Saturday then set default date to Friday with full date format.
If today's date is Sunday then set default date to Friday with full date format.
If any other day , then set default date to previous working day .
So need one sql statement maybe with a case statement .
Now I found these statements which give day of week so now need to do next part which may be a case statement or maybe a function ? This is the part I need assistance pl.
select datename(dw,getdate()) --Monday
select datepart(dw,getdate()) -- 1
SET DATEFIRST 1;
DECLARE #day DATE = SYSDATETIME();
SELECT #day = DATEADD
(
DAY,
CASE
WHEN DATEPART(WEEKDAY, #day) IN (1,2)
THEN -(DATEPART(WEEKDAY, #day)+1)
ELSE -1
END,
#day);
SELECT #day;
So, if the WEEKDAY (or dw) value is 3-6 (Tuesday through Saturday), then subtract one day. Otherwise subtract an additional day for Sunday and an addition two days for Monday.
Fortunately, the value for Sunday is 1 and the value for Monday is 2, so you can just subtract those values for those days.
DECLARE #DefaultDate datetime
SET #DefaultDate =
CASE
WHEN DATEPART(WEEKDAY, GETDATE()) IN (1,2) -- OR (1,7) outside the U.S.
THEN DATEADD(DAY, (-1 - DATEPART(WEEKDAY, GETDATE())), GETDATE())
ELSE
DATEADD(DAY, -1, GETDATE())
END

Converting the name of a day to its integer representation

In SQL server you can use the DATENAME function to get the day of week as a string
declare #date datetime
set #date = '12/16/08'
select datename(dw, #date)
which returns "Tuesday"
and you can use the DATEPART function to get the day of week as an integer
declare #date datetime
set #date = '12/16/08'
select datepart(dw, #date)
Which returns 3
But say I have a varchar that contains the string "Tuesday" and I want to convert it to its integer representation of 3. Sure, I could write out the conversion without much hassle, but I'd much rather use a built-in function. Does such a function exist?
unfortunately there isn't a built in function, but you can create your own like this:
CREATE FUNCTION dbo.WeekDay(#DayOfWeek Varchar(9))
RETURNS INT
AS
BEGIN
DECLARE #iDayofWeek INT
SELECT #iDayofWeek = CASE #DayOfWeek
WHEN 'Sunday' THEN 1
WHEN 'Monday' THEN 2
WHEN 'Tuesday' THEN 3
WHEN 'Wednesday' THEN 4
WHEN 'Thursday' THEN 5
WHEN 'Friday' THEN 6
WHEN 'Saturday' THEN 7
END
RETURN (#iDayofWeek)
END
GO
Rather than write a function, you should create a days of the week table with the description and the numeric value. THen you can simply join to the table to get the numeric.
And if you have days stored multiple ways (likely in a characterbased system), you can put all the variants into the table, so TUE, Tues., Tuesday would all map to the same integer.
Here is a dirty alternative that I use if I'm not running it on massive dataset.
Select CHARINDEX(SUBSTRING('Thursday',1,3), 'MONTUEWEDTHUFRISATSUN') / 3 + 1
Just replace Thursday with a day of your choice or a variable.
How it works: SUBSTRING('Thursday',1,3) basically creates Thu, then charindex finds out the position of thu in the string which is 10. We then divide 10 by length of our day words which is 3 which equals 3, and because I want
Monday to equal 1
Tuesday to equal 2
Wednesday to equal 3
Thursday to equal 4
I add 1 to the end
so the result is 4.
Hope that helps someone, but I agree it probably isn't the best solution.
Note: You can also order a result set by day number by using it like so:
SELECT ID,DayNamesColumn from mytable ORDER BY CHARINDEX(SUBSTRING(DayNamesColumn ,1,3), 'MONTUEWEDTHUFRISATSUN') / 3 + 1
Well 6 years later and several version of SQL Server but there still no built-in function to do this (as far as I know). Not sure if sql-server-2014 will something to do this.
I took similar approach to #RussBradberry just done with IF statements.
CREATE FUNCTION dbo.WeekDayInt (#DayOfWeekName VARCHAR(10))
RETURNS INT
AS
BEGIN
DECLARE #DayWeekNumber INT
IF #DayOfWeekName = 'Sunday' SET #DayWeekNumber = 1
IF #DayOfWeekName = 'Monday' SET #DayWeekNumber = 2
IF #DayOfWeekName = 'Tuesday' SET #DayWeekNumber = 3
IF #DayOfWeekName = 'Wednesday' SET #DayWeekNumber = 4
IF #DayOfWeekName = 'Thursday' SET #DayWeekNumber = 5
IF #DayOfWeekName = 'Friday' SET #DayWeekNumber = 6
IF #DayOfWeekName = 'Saturday' SET #DayWeekNumber = 7;
RETURN (#DayWeekNumber)
END
or as alternative it can be done this way, which can be a little faster because it will return value as soon as match is encountered and not try to evaluate other values.
CREATE FUNCTION dbo.WeekDayInt (#DayOfWeekName VARCHAR(10))
RETURNS INT
AS
BEGIN
IF #DayOfWeekName = 'Sunday' RETURN 1
IF #DayOfWeekName = 'Monday' RETURN 2
IF #DayOfWeekName = 'Tuesday' RETURN 3
IF #DayOfWeekName = 'Wednesday' RETURN 4
IF #DayOfWeekName = 'Thursday' RETURN 5
IF #DayOfWeekName = 'Friday' RETURN 6
IF #DayOfWeekName = 'Saturday' RETURN 7;
RETURN 0;
END
You can use the following select to get the iso weekday ordinal of date 2017-12-15 with respect to (e.g. regardless of) the current setting of ##datefirst which determines the first day of the week. E.g. set datefirst = 1 for monday.
select
w.weekday_id_iso8601,
w.weekday_id_datepart,
w.weekday_name
from (
values
(7, 'Monday'),
(8, 'Tuesday'),
(9, 'Wednesday'),
(10, 'Thursday'),
(11, 'Friday'),
(12, 'Saturday'),
(13, 'Sunday'))
t(weekday_id, weekday_name)
cross apply (
select
t.weekday_id - 6 weekday_id_iso8601,
(t.weekday_id - ##datefirst + 1) % 7 + 1 weekday_id_datepart,
t.weekday_name
) w
where w.weekday_id_datepart = datepart(weekday, '2017-12-15')
I disagree with the answer about adding a lookup table, since in this case, the values are limited and will never change. The lookup table join will just add cost.
IMHO; since you have limited values, I would just use a case statement in my views. It's not pretty, but it's probably the fastest way to do it.
This may not serve a practical purpose, but I thought I'd figure it out just for fun. :) The following works.
Remember that when using DATEPART or DATENAME that the value of ##DATEFIRST is important and can change your results. Look up SET DATEFIRST in the online help.
DECLARE
#date_name AS VARCHAR(20)
SET #date_name = 'Monday'
SELECT
DATEPART(dw, my_date)
FROM
(
SELECT CAST('1900-01-01' AS DATETIME) AS my_date UNION
SELECT CAST('1900-01-02' AS DATETIME) AS my_date UNION
SELECT CAST('1900-01-03' AS DATETIME) AS my_date UNION
SELECT CAST('1900-01-04' AS DATETIME) AS my_date UNION
SELECT CAST('1900-01-05' AS DATETIME) AS my_date UNION
SELECT CAST('1900-01-06' AS DATETIME) AS my_date UNION
SELECT CAST('1900-01-07' AS DATETIME) AS my_date
) AS My_Dates
WHERE
DATENAME(dw, my_date) = #date_name
Where DayID is integer value 1 thru 7.
Add DayID to a some base date such as 1899-12-31. (If Sunday is first day of week then use initial date of 1899-12-30)
1900-01-01 was Monday, 1900-01-02 was Tuesday, and so on.
Thus :
select DayID,
datename( weekday, dateadd( day, DayID, '18991231' ) )
In SQL 2014, you can use:
SELECT DATEPART(DW, GetDate()) This will return day of week as integer.