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.
Related
For example:
#dtBegin = '2012-06-29'
#input = 20
I want the output to be '2012-07-27'.
I had to tackle the same problem in my project. Gordon Lionoff's solution got me on the right track but did not always produce the right result. I also have to take in account dates that start in a weekend. I.e. adding 1 business day to a saturday or sunday should result in a monday. This is the most common approach to handling business day calculation.
I've created my own solution based on Gordon Linoff's function and Patrick McDonald's excellent C# equivalent
NOTE: My solution only works if DATEFIRST is set to the default value of 7. If you use a different DATEFIRST value, you will have to change the 1, 7 and (1,7,8,9,10) bits.
My solution consists of two functions. An "outer" function that handles edge cases and an "inner" function that performs the actual calculation. Both functions are table-valued functions so they will actually be expanded into the implementing query and fed through the query optimizer.
CREATE FUNCTION [dbo].[UTL_DateAddWorkingDays]
(
#date datetime,
#days int
)
RETURNS TABLE AS RETURN
(
SELECT
CASE
WHEN #days = 0 THEN #date
WHEN DATEPART(dw, #date) = 1 THEN (SELECT Date FROM [dbo].[UTL_DateAddWorkingDays_Inner](DATEADD(d, 1, #date), #days - 1))
WHEN DATEPART(dw, #date) = 7 THEN (SELECT Date FROM [dbo].[UTL_DateAddWorkingDays_Inner](DATEADD(d, 2, #date), #days - 1))
ELSE (SELECT Date FROM [dbo].[UTL_DateAddWorkingDays_Inner](#date, #days))
END AS Date
)
As you can see, the "outer" function handles:
When adding no days, return the original date. This will keep saturday and sunday dates intact.
When adding days to a sunday, start counting from monday. This consumes 1 day.
When adding days to a saturday, start counting from monday. This consumes 1 day.
In all other cases, perform the usual calculation
_
CREATE FUNCTION [dbo].[UTL_DateAddWorkingDays_Inner]
(
#date datetime,
#days int
)
RETURNS TABLE AS RETURN
(
SELECT
DATEADD(d
, (#days / 5) * 7
+ (#days % 5)
+ (CASE WHEN ((#days%5) + DATEPART(dw, #date)) IN (1,7,8,9,10) THEN 2 ELSE 0 END)
, #date) AS Date
)
The "inner" function is similar to Gordon Linoff's solution, except it accounts for dates crossing weekend boundaries but without crossing a full week boundary.
Finally, I created a test script to test my function. The expected values were generated using Patrick McDonald's excellent C# equivalent and I randomly cross-referenced this data with this popular calculator.
You can do this without resorting to a calendar table or user defined function:
dateadd(d,
(#input / 5) * 7 + -- get complete weeks out of the way
mod(#input, 5) + -- extra days
(case when ((#input%5) + datepart(dw, #dtbegin)%7) in (7, 1, 8) or
((#input%5) + datepart(dw, #dtbegin)%7) < (#input%5)
then 2
else 0
end),
#dtbegin
)
I'm not saying this is pretty. But sometimes arithmetic is preferable to a join or a loop.
This is what I've tried:
CREATE function [dbo].[DateAddWorkDay]
(#days int,#FromDate Date)
returns Date
as
begin
declare #result date
set #result = (
select b
from
(
SELECT
b,
(DATEDIFF(dd, a, b))
-(DATEDIFF(wk, a, b) * 2)
-(CASE WHEN DATENAME(dw, a) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, b) = 'Saturday' THEN 1 ELSE 0 END)
-COUNT(o.Holiday_Date)
as workday
from
(
select
#FromDate as a,
dateadd(DAY,num +#days,#FromDate) as b
from (select row_number() over (order by (select NULL)) as num
from Information_Schema.columns
) t
where num <= 100
) dt
left join Holiday o on o.Holiday_Date between a and b and DATENAME(dw, o.Holiday_Date) not in('Saturday','Sunday')
where DATENAME(dw, b) not in('Saturday','Sunday')
and b not in (select Holiday_Date from OP_Holiday where Holiday_Date between a and b)
group by a,b
) du
where workday =#days
)
return #result
end
Where Holiday is a table with holiday_date as a reference for holiday.
I realize I'm about 8 years late to this party... But I took Martin's answer and updated it to:
1. a single scalar function instead of 2 nested table-valued functions
I tested using his original test script and my function passes too. Also, it seems the rebuild to a scalar function has a slight positive impact on performance. Both versions seem to benefit equally from 'buffer caching', the scalar version performing up to 25% better non-cached and up to 40% better cached. Disclaimer: I just ran both versions a bunch of times and recorded the times, I did not do any decent performance testing.
2. include support for DATEFIRST is either Monday, Saturday or Sunday
I feel a UDF should be agnostic to the datefirst setting. I'm in Europe and Monday is the default here. The original function would not work without adaptation.
According to wikipedia Monday, Saturday and Sunday are the only real world first days of the week. Support for other could easily be added, but would make the code more bulky and I have a hard time envisioning a real world use case.
CREATE FUNCTION dbo.fn_addWorkDays
(
#date datetime,
#days int
)
RETURNS DATETIME
AS
BEGIN
IF NOT ##DATEFIRST IN (1,6,7) BEGIN --UNSUPPORTED DATE FIRST
RETURN NULL
/* MONDAY = FRIST DAY */
END ELSE IF #days = 0 BEGIN
RETURN #date
END ELSE IF ##DATEFIRST = 1 AND DATEPART(dw, #date) = 7 BEGIN --SUNDAY
SET #date = DATEADD(d, 1, #date)
SET #days = #days - 1
END ELSE IF ##DATEFIRST = 1 AND DATEPART(dw, #date) = 6 BEGIN --SATURDAY
SET #date = DATEADD(d, 2, #date)
SET #days = #days - 1
/* SATURDAY = FRIST DAY */
END ELSE IF ##DATEFIRST = 7 AND DATEPART(dw, #date) = 2 BEGIN --SUNDAY
SET #date = DATEADD(d, 1, #date)
SET #days = #days - 1
END ELSE IF ##DATEFIRST = 7 AND DATEPART(dw, #date) = 1 BEGIN --SATURDAY
SET #date = DATEADD(d, 2, #date)
SET #days = #days - 1
/* SUNDAY = FRIST DAY */
END ELSE IF ##DATEFIRST = 7 AND DATEPART(dw, #date) = 1 BEGIN --SUNDAY
SET #date = DATEADD(d, 1, #date)
SET #days = #days - 1
END ELSE IF ##DATEFIRST = 7 AND DATEPART(dw, #date) = 7 BEGIN --SATURDAY
SET #date = DATEADD(d, 2, #date)
SET #days = #days - 1
END
DECLARE #return AS dateTime
SELECT #return =
DATEADD(d
, (#days / 5) * 7
+ (#days % 5)
+ (CASE
/* MONDAY = FRIST DAY */
WHEN ##DATEFIRST = 1 AND ((#days%5) + DATEPART(dw, #date)) IN (6,7,8,9) THEN 2
/* SATURDAY = FRIST DAY */
WHEN ##DATEFIRST = 7 AND ((#days%5) + DATEPART(dw, #date)) IN (1,2,8,9,10) THEN 2
/* SUNDAY = FRIST DAY */
WHEN ##DATEFIRST = 7 AND ((#days%5) + DATEPART(dw, #date)) IN (1,7,8,9,10,11) THEN 2
ELSE 0
END)
, #date)
RETURN #return
END
I hope this might benefit someone!
you can use the below mentioned code for exclude weekends
go
if object_id('UTL_DateAddWorkingDays') is not null
drop function UTL_DateAddWorkingDays
go
create FUNCTION [dbo].[UTL_DateAddWorkingDays]
(
#date datetime,
#daysToAdd int
)
RETURNS date
as
begin
declare #daysToAddCnt int=0,
#Dt datetime
declare #OutTable table
(
id int identity(1,1),
WeekDate date,
DayId int
)
while #daysToAdd>0
begin
set #Dt=dateadd(day,#daysToAddCnt,#date)
--select #daysToAddCnt cnt,#Dt date,DATEPART(weekday,#Dt) dayId,#daysToAdd daystoAdd
if(DATEPART(weekday,#Dt) <>7 and DATEPART(weekday,#Dt)<>1)
begin
insert into #outTable (WeekDate,DayId)
select #Dt,DATEPART(weekday,DATEADD(day,#daysToAddCnt,#Dt))
set #daysToAdd=#daysToAdd-1
end
set #daysToAddCnt=#daysToAddCnt+1
end
select #Dt=max(WeekDate) from #outTable
return #Dt
end
what about this?
declare #d1 date='2012-06-29'
declare #days int=20
select dateadd(dd,#days,#d1)
select dateadd(dd,case DATEPART(dw,t1.d) when 6 then +2 when 7 then +1 else +0 end,t1.d)
from
(
select dateadd(dd,CEILING((convert(float,#days)/5)*2)+#days,#d1)d
)t1
i found how many we in the range by CEILING((convert(float,#days)/5)*2)
then i added them to date and at the end i check if is a saturday or sunday and i add 1 or 2 days.
i have an ssis Package which runs on business days (mon-Fri). if i receive file on tuesday , background(DB), it takes previous business day date and does some transactions. If i run the job on friday, it has to fetch mondays date and process the transactions.
i have used the below query to get previous business date
Select Convert(varchar(50), Position_ID) as Position_ID,
TransAmount_Base,
Insert_Date as InsertDate
from tblsample
Where AsOfdate = Dateadd(dd, -1, Convert(datetime, Convert(varchar(10), '03/28/2012', 101), 120))
Order By Position_ID
if i execute this query i'll get the results of yesterdays Transactios. if i ran the same query on monday, it has to fetch the Fridays transactions instead of Sundays.
SELECT DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 0, GETDATE()))
I prefer to use DATENAME for things like this over DATEPART as it removes the need for Setting DATEFIRST And ensures that variations on time/date settings on local machines do not affect the results. Finally DATEDIFF(DAY, 0, GETDATE()) will remove the time part of GETDATE() removing the need to convert to varchar (much slower).
EDIT (almost 2 years on)
This answer was very early in my SO career and it annoys me everytime it gets upvoted because I no longer agree with the sentiment of using DATENAME.
A much more rubust solution would be:
SELECT DATEADD(DAY, CASE (DATEPART(WEEKDAY, GETDATE()) + ##DATEFIRST) % 7
WHEN 1 THEN -2
WHEN 2 THEN -3
ELSE -1
END, DATEDIFF(DAY, 0, GETDATE()));
This will work for all language and DATEFIRST settings.
This function returns last working day and takes into account holidays and weekends. You will need to create a simple holiday table.
-- =============================================
-- Author: Dale Kilian
-- Create date: 2019-04-29
-- Description: recursive function returns last work day for weekends and
-- holidays
-- =============================================
ALTER FUNCTION dbo.fnGetWorkWeekday
(
#theDate DATE
)
RETURNS DATE
AS
BEGIN
DECLARE #importDate DATE = #theDate
DECLARE #returnDate DATE
--Holidays
IF EXISTS(SELECT 1 FROM dbo.Holidays WHERE isDeleted = 0 AND #theDate = Holiday_Date)
BEGIN
SET #importDate = DATEADD(DAY,-1,#theDate);
SET #importDate = (SELECT dbo.fnGetWorkWeekday(#importDate))
END
--Satruday
IF(DATEPART(WEEKDAY,#theDate) = 7)
BEGIN
SET #importDate = DATEADD(DAY,-1,#theDate);
SET #importDate = (SELECT dbo.fnGetWorkWeekday(#importDate))
END
--Sunday
IF(DATEPART(WEEKDAY,#theDate) = 1)
BEGIN
SET #importDate = DATEADD(DAY,-2,#theDate);
SET #importDate = (SELECT dbo.fnGetWorkWeekday(#importDate))
END
RETURN #importDate;
END
GO
Then how about:
declare #dt datetime='1 dec 2012'
select case when 8-##DATEFIRST=DATEPART(dw,#dt)
then DATEADD(d,-2,#dt)
when (9-##DATEFIRST)%7=DATEPART(dw,#dt)%7
then DATEADD(d,-3,#dt)
else DATEADD(d,-1,#dt)
end
The simplest solution to find the previous business day is to use a calendar table with a column called IsBusinessDay or something similar. The your query is something like this:
select max(BaseDate)
from dbo.Calendar c
where c.IsBusinessDay = 0x1 and c.BaseDate < #InputDate
The problem with using functions is that when (not if) you have to create exceptions for any reason (national holidays etc.) the code quickly becomes unmaintainable; with the table, you just UPDATE a single value. A table also makes it much easier to answer questions like "how many business days are there between dates X and Y", which are quite common in reporting tasks.
You can easily make this a function call, adding a second param to replace GetDate() with whatever date you wanted.
It will work for any day of the week, at any date range, if you change GetDate().
It will not change the date if the day of week is the input date (GetDate())
Declare #DayOfWeek As Integer = 2 -- Monday
Select DateAdd(Day, ((DatePart(dw,GetDate()) + (7 - #DayOfWeek)) * -1) % 7, Convert(Date,GetDate()))
More elegant:
select DATEADD(DAY,
CASE when datepart (dw,Getdate()) < 3 then datepart (dw,Getdate()) * -1 + -1 ELSE -1 END,
cast(GETDATE() as date))
select
dateadd(dd,
case DATEPART(dw, getdate())
when 1
then -2
when 2
then -3
else -1
end, GETDATE())
thanks for the tips above, I had a slight variant on the query in that my user needed all values for the previous business date. For example, today is a Monday so he needs everything between last Friday at midnight through to Saturday at Midnight. I did this using a combo of the above, and "between", just if anyone is interested. I'm not a massive techie.
-- Declare a variable for the start and end dates.
declare #StartDate as datetime
declare #EndDate as datetime
SELECT #StartDate = DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 0, GETDATE()))
select #EndDate = #StartDate + 1
select #StartDate , #EndDate
-- Later on in the query use "between"
and mydate between #StartDate and #EndDate
I want to be able to pass in a day number like 1, 2, 3 or 7 and it will return the day name like Sunday, Monday, Tuesday or Saturday. I know there is the option of using a case statement but I would like to do this using SQL commands, would this be at all possible?
DECLARE #m VARCHAR
SET #m=1
SELECT CASE WHEN #m=1 THEN 'Sunday' END
I have already commented on this question when looking for an answer but user #harper suggested that I should submit a new question with a full description.
EDIT:
there is currently answers are given for case statement mostly except one . so again now i am putting my question again here is
" I would like to do this using SQL commands, would this be at all possible?"
Try this :
declare #m varchar
set #m=1
SELECT DATENAME(DW,CAST(#m AS INT))
SQL Server Denali has the CHOOSE function that will make this more concise. In the meantime just use CASE inside the UDF.
CREATE FUNCTION dbo.WeekDay(#d int)
RETURNS VARCHAR(9)
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS
BEGIN
RETURN
(
SELECT
CASE #d
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
)
END
CREATE FUNCTION dbo.udf_DayOfWeek(#dtDate DATETIME)
RETURNS VARCHAR(10)
AS
BEGIN
DECLARE #rtDayofWeek VARCHAR(10)
SELECT #rtDayofWeek = CASE DATEPART(weekday,#dtDate)
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
RETURN (#rtDayofWeek)
END
GO
-- Call this function like this:
SELECT dbo.udf_DayOfWeek(GETDATE()) AS DayOfWeek
orignally from : SQL SERVER – UDF – Get the Day of the Week Function
SELECT DATENAME(DW,CAST(a AS INT))
Here we can change the value of a as 0 to 6
Default, 0-Monday to 6- Sunday.
If we use a=7 then it will be calculated as 0, because 7-7=0.
I seem to be asking a lot of SQL questions at the moment. (I would normally write a program to sort the data into a report table, however at the moment that is not possible, and needs to be done using SQL)
The Question
I need a where clause that returns results with the next working day. i.e. Monday 01/01/01 the next working day would be Tuesday 02/01/01 which could be achieved with a simple date add. However on a Friday 05/01/01 the next working day is Monday 08/01/01. Is there anything built in to help cope with this easily?
Thanks for your advice.
The key is to use the DATEPART(weekday,#date) function, it'll return the day of the week, so if it's saturday or sunday you just add one or two to the current date to get the desired result.
You can create a user defined function to do so easily, for example Pinal Dave has this
CREATE FUNCTION dbo.udf_GetPrevNextWorkDay (#dtDate DATETIME, #strPrevNext VARCHAR(10))
RETURNS DATETIME
AS
BEGIN
DECLARE #intDay INT
DECLARE #rtResult DATETIME
SET #intDay = DATEPART(weekday,#dtDate)
--To find Previous working day
IF #strPrevNext = 'Previous'
IF #intDay = 1
SET #rtResult = DATEADD(d,-2,#dtDate)
ELSE
IF #intDay = 2
SET #rtResult = DATEADD(d,-3,#dtDate)
ELSE
SET #rtResult = DATEADD(d,-1,#dtDate)
--To find Next working day
ELSE
IF #strPrevNext = 'Next'
IF #intDay = 6
SET #rtResult = DATEADD(d,3,#dtDate)
ELSE
IF #intDay = 7
SET #rtResult = DATEADD(d,2,#dtDate)
ELSE
SET #rtResult = DATEADD(d,1,#dtDate)
--Default case returns date passed to function
ELSE
SET #rtResult = #dtDate
RETURN #rtResult
END
GO
CREATE FUNCTION dbo.uf_GetNextWorkingDay (#givenDate DATETIME)
RETURNS DATETIME
AS
BEGIN
DECLARE #workingDate DATETIME
IF (DATENAME(dw , #givenDate) = 'Friday')
BEGIN
SET #workingDate = DATEADD(day, 3, #givenDate)
END
ELSE IF (DATENAME(dw , #givenDate) = 'Saturday')
BEGIN
SET #workingDate = DATEADD(day, 2, #givenDate)
END
ELSE
BEGIN
SET #workingDate = DATEADD(day, 1, #givenDate)
END
RETURN #workingDate
END
A good article http://ryanfarley.com/blog/archive/2005/02/14/1685.aspx
You could do this with a simple day check and add 3 days rather than one if its a Friday. However, do you need to take into consideration public holidays though?
All Credit to Cashif -- I modified his to include a Holiday table (tblHolidays with a date field HolDate) which is very lightweight -- about 10 rows a year if you're lucky enough to get that many days off!
My version returns date type (which I find easier to work with). I also run thru this more than once -- if Thursday is your startday and Friday is a holiday, you have to again add 2 more days to get to Monday (or the next working day). Then it checkes to make sure the next week doesn't start with a holiday.
CREATE FUNCTION [dbo].[GetNextWorkingDay] (#givenDate DATE)
RETURNS DATE
AS
BEGIN
DECLARE #workingDate DATETIME
IF (DATENAME(dw , #givenDate) = 'Friday')
BEGIN
SET #workingDate = DATEADD(day, 3, #givenDate)
END
ELSE IF (DATENAME(dw , #givenDate) = 'Saturday')
BEGIN
SET #workingDate = DATEADD(day, 2, #givenDate)
END
ELSE
BEGIN
SET #workingDate = DATEADD(day, 1, #givenDate)
END
while ((Select count(*) from tblHolidays where holdate = #workingDate) > 0)
begin
set #workingDate = dateadd(dd,1,#WorkingDate)
end
-- if adding a day makes it a Saturday, add 2 more to get to Monday (and test to make sure the week doesn't start with a holiday)
IF (DATENAME(dw , #workingDate) = 'Saturday')
BEGIN
SET #workingDate = DATEADD(day, 2, #workingDate)
END
while ((Select count(*) from tblHolidays where holdate = #workingDate) > 0)
begin
set #workingDate = dateadd(dd,1,#WorkingDate)
end
RETURN #workingDate
END
... of course you should refactor so the code doesn't repeat, and include a while clause to repeat only as many times as needed to get to a working day, but I have a deadline... that'll be for another less hectic day.
Here's what I did for a one-off application:
WHILE EXISTS (SELECT * FROM Holidays WHERE CONVERT(VARCHAR, HolidayDate,101) = CONVERT(VARCHAR,#DateVariable 101 ) OR DATENAME(WEEKDAY, #DateVariable)='SATURDAY' OR DATENAME(WEEKDAY, #DateVariable)='SUNDAY')
BEGIN
SET #DateVariable = DateAdd(day,1,#DateVariable)
PRINT #DateVariable -- If you want
END
Note that, our Holidays table stores all holidays for the past and future years.
You could do this with a simple case statement.
select case when datepart(dw, getdate()) >= 6 then getdate() + (9 - datepart(dw, getdate())) else getdate() + 1 end
What you need is a calendar table. Getting the next working days is not so simple if you need to account for holidays other than the weekend. The table basically contains just two columns Date and an integer field indicating whether it is a working/non working day- but there can be other columns for - example quarter etc as well.
This table is populated once a year and then maintained as necessary. Getting the result for next working day then becomes as simple as a query like this.
SELECT field1,filed2 from your table T where your date_Field = (SELECT min(date) From calendar table where WorkingDay = 1 and date > GetDate())
/P
How about somethin like this?
select * from table
where (date = dateadd(dd,1,#today) and datepart(weekday,#today) not in (6,0) ) --its not friday or saturday
or (date = dateadd(dd,2,#today) and datepart(weekday,#today) = 0) -- its saturday
or (date = dateadd(dd,3,#today) and datepart(weekday,#today) = 6) --its friday
the date attribute should have the same time as #today or else you have to also use between
It's been basically answered above, but it took me a while to get it and I thought maybe this will help somebody. Is used a simple CASE-WHEN.
This is a check in order to find out which days are weekdays
DATEPART(dw, date) -> MON through FRI = 1,2,3,4,5 SAT = 6, SUN = 7
This is the CASE-WHEN:
CASE
WHEN DATEPART(weekday, date) <= 5 THEN date -- weekdays, no change
WHEN DATEPART(weekday, date) = 6 THEN date + 2 -- SAT + 2 = MON
WHEN DATEPART(weekday, date) = 6 THEN date + 1 -- SUN + 1 = MON
END AS 'WEEKDAY_DATES'
Check, if the statement actually gets you weekdays only:
CASE
WHEN DATEPART(weekday, date) <= 5 THEN DATENAME(weekday, date)
WHEN DATEPART(weekday, date) = 6 THEN DATENAME(weekday, date + 2)
WHEN DATEPART(weekday, date) = 6 THEN DATENAME(weekday, date + 1)
END AS 'WEEKDAY_NAMES'
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