SET DATEFIRST in FUNCTION - sql-server

I want to SET DATEFIRST in my function but it is not allowed.
SET DATEFIRST 1
I can add the code in a SP and call the SP from the function but I am not keen on doing that.
I can SET the DATEFIRST before I call my function but I am not keen on doing that as well.
Any other work around?
EDIT
Below is the code I want to use in my FUNCTION to return the total working days of the month. But I cant add this code into the FUNCTION because of my DATEFIRST
DECLARE #my int
DECLARE #myDeduct int
DECLARE #day INT
DECLARE #mydate DATETIME
DECLARE #TotalDays INT
SET #mydate = GETDATE()
SET #myDeduct = 0
IF (##DATEFIRST + DATEPART(DW, #mydate)) % 7 not in (0,1)
SET DateFirst 1 -- Set it monday=1 (value)
--Saturday and Sunday on the first and last day of a month will Deduct 1
IF (DATEPART(weekday,(DATEADD(dd,-(DAY(#mydate)-1),#mydate))) > 5)
SET #myDeduct = #myDeduct + 1
IF (DATEPART(weekday,(DATEADD(dd,-(DAY(DATEADD(mm,1,#mydate))),DATEADD(mm,1,#mydate)))) > 5)
SET #myDeduct = #myDeduct + 1
SET #my = day(DATEADD(dd,-(DAY(DATEADD(mm,1,#mydate))),DATEADD(mm,1,#mydate)))
Set #TotalDays = (select (((#my/7) * 5 + (#my%7)) - #myDeduct))
Select #TotalDays

Instead of
SET DATEFIRST 1
You can do
SELECT (DATEPART(weekday, GETDATE()) + ##DATEFIRST - 2) % 7 + 1

My usual workaround is to use "known-good" dates for my comparisons.
Say, for instance, that I need to check that a date is a saturday. Rather than relying on DATEFIRST or language settings (for using DATENAME), I instead say:
DATEPART(weekday,DateToCheck) = DATEPART(weekday,'20120714')
I know that 14th July 2012 was a Saturday, so I've performed the check without relying on any external settings.
The expression (DATEPART(weekday,DateToCheck) + ##DATEFIRST) % 7 will always produce the value 0 for Saturday, 1 for Sunday, 2 for Monday, etc.
So, I'd advise you to create a table:
CREATE TABLE WorkingDays (
NormalisedDay int not null,
DaysInMonth int not null,
WorkingDays int not null
)
Populating this table is a one off exercise. NormalisedDay would be the value computed by the expression I've given above.
To compute the DaysInMonth given a particular date, you can use the expression:
DATEDIFF(day,
DATEADD(month,DATEDIFF(month,0,DateToCheck),0),
DATEADD(month,DATEDIFF(month,'20010101',DateToCheck),'20010201'))
Now all your function has to do is look up the value in the table.
(Of course, all of the rows where DaysInMonth is 28 will have 20 as their result. It's only the rows for 29,30 and 31 which need a little work to produce)

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 in your function:
(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 DATEFIRST setting):
SET DATEFIRST 1
DATEPART(dw, '2019-02-04 00:00:00')

If you need Monday as firstday follow this code snippet
declare #MyDate datetime = getdate()
select CASE WHEN DATEPART(DW,#MyDate) = 1
THEN 7
WHEN DATEPART(DW,#MyDate) <= 7
THEN DATEPART(DW,#MyDate) - 1
END

Related

SQL Server : how do you exclude weekends using datediff?

I am still learning SQL so please bare that in mind. I have a query that returns me the average days for a specific range, although my range does not account for weekends & holidays. Holidays may be a little tricky but how do I exclude weekends from my range?
For example I have a range 02-01-18 to 02-15-18 where the datediff is 14 days, but how do I get SQL to identifying which days in that range were weekends and if they were to exclude them from my datediff?
My query is
SELECT
AVG(1.00 * DATEDIFF(DAY, xx, yy)) AS DayDiff
FROM
datebase1.dbo.table1
WHERE
MONTH(datecompleted) = MONTH(DATEADD(month, -1, current_timestamp))
AND YEAR(datecompleted) = YEAR(DATEADD(month, -1, current_timestamp))
AND ApprovalRequiredFrom = 'pp'
I do have a calendar I can source which tells me the date and the name of the day, but I want to avoid having to do this. I want to be able to exclude the weekends from my range to get me a more accurate result.
Thanks
To exclude weekends, you need to filter Saturdays and Sundays from both your comparing dates (xx and yy). To do so you use the DATEPART function with the WEEKDAY parameter. The result is a number from 1 to 7 indicating which day of the week it is.
-- 2018-01-01 is a monday
SELECT DATEPART(WEEKDAY, '2018-01-01')
-- Result: 2
The problem is that different database configurations have the date related to the value "1" changed, so maybe the day of week "1" means Sunday for some and Mondays for others. To unify this, you can change the default with SET DATEFIRST.
SET DATEFIRST 1 -- 1: Monday, 7: Sunday
-- 2018-01-01 is a monday
SELECT DATEPART(WEEKDAY, '2018-01-01')
-- Result: 1
Another solution that is datefirst agnostic is to use the ##DATEFIRST session value directly on your expression. The ##DATEFIRST holds the value we set on the SET DATEFIRST statement, or the database default. Please notice that the result is the same, even changing DATEFIRST.
SET DATEFIRST 7 -- 1: Sunday, 2: Monday
-- 2018-01-01 is a monday
SELECT (DATEPART(WEEKDAY, '2018-01-01') + ##DATEFIRST) % 7
-- Result: 2
SET DATEFIRST 1 -- 1: Monday, 7: Sunday
-- 2018-01-01 is a monday
SELECT (DATEPART(WEEKDAY, '2018-01-01') + ##DATEFIRST) % 7
-- Result: 2
For your example, you need to filter xx and yy dates to not be weekends. Add the following to your WHERE clause:
WHERE
--...
AND (DATEPART(WEEKDAY, xx) + ##DATEFIRST) % 7 NOT IN (0, 1)
AND (DATEPART(WEEKDAY, yy) + ##DATEFIRST) % 7 NOT IN (0, 1)
Because need to work with the old MySQL 5.1 server, just got a chance to try a "math" way to calculate no. of SAT / SUN to subtract from:
Note: MySQL's "weekday" function returns 0 for Mon, 5 for SAT and 6 for SUN, thus you see below SQL has some magic no. with 5 and 6.
Sample:
select floor((datediff (ed, st)+1) / 7)*2 /*complete week's weekends*/
+ case when floor((datediff (ed, st) +1) % 7) between 0 and 6 /*additional weekends besides complete weeks*/
then case when weekday(ed) >= weekday(st) then least(floor((datediff (ed, st) +1) % 7), greatest(least(6, weekday(ed)) - greatest(5, weekday(st)) + 1,0))
else least(floor((datediff (ed, st) +1) % 7), greatest(least(6, weekday(ed)+7) - greatest(5, weekday(st)) + 1,0)) end
else 0
end as num_of_sat_and_sun
from (select '2019-01-07' as st, '2019-01-12' as ed) x

How to handle DATEFIRST when using DATEPART

-- SET DATEFIRST to U.S. English default value of 7.
SET DATEFIRST 7;
SELECT
##DATEFIRST;
SELECT
GETDATE()
, DATEPART(dw , GETDATE()) AS DayOfWeek;
-- January 1, 1999 is a Friday. Because the U.S. English default
-- specifies Sunday as the first day of the week, DATEPART of 1999-1-1
-- (Friday) yields a value of 6, because Friday is the sixth day of the
-- week when you start with Sunday as day 1.
SET DATEFIRST 3;
SELECT
##DATEFIRST;
-- Because Wednesday is now considered the first day of the week,
-- DATEPART now shows that 1999-1-1 (a Friday) is the third day of the
-- week. The following DATEPART function should return a value of 3.
SELECT
GETDATE()
, DATEPART(dw , GETDATE()) AS DayOfWeek;
SET DATEFIRST 7;
How do we handle getting the DATEPART (1 = Sunday always) irregardless of DATEFIRST setting?
I really don't want to do a case and subtract...
this always seems ridiculous to me, how about
select datediff(day,0, getdate()) % 7
where 6 represents Sunday
or you could do
select (datediff(day,0, '2016-07-31') - 5) % 7
to get Sun = 1, Mon = 2, Tue = 3 ... etc
or you could do this fiddle
select (datepart(weekday,get_date()) + ##datefirst - 1) % 7 + 1
seems to work for all datepart
set datefirst 5
select (datepart(weekday,'2016-07-31') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-01') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-02') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-03') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-04') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-05') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-06') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-07') + ##datefirst - 1) % 7 + 1
This code selects Monday as the first day of week whatever the setting in your engine:
((datepart(DW, #YourDateVariable) + ##DATEFIRST + 5) % 7) + 1
by adding ##DATEFIRST value before the modulus operator it neglects the datefirst setting in your SQL engine.
The value 5 is to make Monday as the first day of the week
To make Sunday as the first day of the week add 6
to make saturday as the first day of the week then add 0
and so on the rest of the day weeks.
Perhaps not the most elegant, but instead of doing the subtraction you can just set it to 7 and then back to what ever it was after your DATEPART
SET DATEFIRST 7;
SELECT DATEPART(dw , GETDATE()) --6
SET DATEFIRST 3;
DECLARE #currentDatefirst int = ##DATEFIRST
SELECT ##DATEFIRST --3
SET DATEFIRST 7;
SELECT DATEPART(dw , GETDATE()) --6
SET DATEFIRST #currentDatefirst
SELECT ##DATEFIRST --3

Creating a date from Week of month and Day of week in SQL server

I have to get/create date from the user input of week of month (week number in that month - 1st,2nd,3rd,4th and last) and day of week (sunday,monday..) in SQL server.
Examples:
4th Sunday of every month, Last Friday of every month, First Monday etc.
I was able to do it easily in .net but SQL server does seem limited in the date functions.
I am having to use lot of logic to get the date. To calculate the date using the above two parameters I had to use lot of datepart function.
Any suggestions on how to come up with the optimal SQL query for such a function?
I created a function other day for another OP GET Month, Quarter based on Work Week number
This function takes the current year as default it can be further modified to take Year as a parameter too.
an extension to that function can produce the results you are looking for ....
WITH X AS
(
SELECT TOP (CASE WHEN YEAR(GETDATE()) % 4 = 0 THEN 366 ELSE 365 END)-- to handle leap year
DATEADD(DAY
,ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1
, CAST(YEAR(GETDATE()) AS VARCHAR(4)) + '0101' )
DayNumber
From master..spt_values
),DatesData AS(
SELECT DayNumber [Date]
,DATEPART(WEEKDAY,DayNumber) DayOfTheWeek
,DATEDIFF(WEEK,
DATEADD(WEEK,
DATEDIFF(WEEK, 0, DATEADD(MONTH,
DATEDIFF(MONTH, 0, DayNumber), 0)), 0)
, DayNumber- 1) + 1 WeekOfTheMonth
FROM X )
SELECT * FROM DatesData
WHERE DayOfTheWeek = 6 -- A function would expect these two parameters
AND WeekOfTheMonth = 4 -- #DayOfTheWeek and #WeekOfTheMonth
Here is a general formula:
declare #month as datetime --set to the first day of the month you wish to use
declare #week as int --1st, 2nd, 3rd...
declare #day as int --Day of the week (1=sunday, 2=monday...)
--Second monday in August 2015
set #month = '8/1/2015'
set #week = 2
set #day = 2
select dateadd(
day,
((7+#day) - datepart(weekday, #month)) % 7 + 7 * (#week-1),
#month
)
You can also find the last, 2nd to last... etc with this reverse formula:
--Second to last monday in August 2015
set #month = '8/1/2015'
set #week = 2
set #day = 2
select
dateadd(
day,
-((7+datepart(weekday, dateadd(month,1,#month)-1)-#day)) % 7 - 7 * (#week-1),
dateadd(month,1,#month)-1
)

Stored Procedure to check if four weeks with less then two records

I am working on a stored procedure. The input is going to be a date and ID and the procedure is going to set a value to true if there are 4 weeks with less then 2 inputs per week.
It has to take in consideration that I might pass an early date with no records in the database.
I couldn't format the code. I don't know why?
So far I got that with previous help from you guys:
CREATE proc [dbo].[sp_test] (#id int, #d date)
as
declare #WeekFirstRecord as int
declare #WeeksWithNoRecords as int
SET #WeekFirstRecord = datepart(week,(select Min(ZeroPointIncidentDate) from EmployeeZeroPointIncidents where ZeroPointIncidentDate > #d))
SET #WeeksWithNoRecords = datepart(week, #WeekFirstRecord) - datepart(week, #d)
select case when sum(c) + #WeeksWithNoRecords >= 4 then 'true' else 'false' end status
from (
select c = count(*) over (partition by EmpId, datepart(week, ZeroPointIncidentDate))
from EmployeeZeroPointIncidents
where EmpId = #id and ZeroPointIncidentDate >= #d
) a
where c = 1
In my data only the weeks with the stars have less than two inputs and if I pass the date 7-7-2015 is going to set the output value to true
Any help will be appreciated. Do I need to iterate through every record and set a counter if less then two inputs or there is an easier way ?
ID Date
1 7-7-2015
2 6-23-2015
3 6-12-2015
1 7-8-2015
1 7-14-2015 *
1 7-21-2015 *
1 7-27-2015
1 7-28-2015
1 7-29-2015
1 7-30-2015
1 8-3-2015 *
1 8-11-2015 *
If I had week Jul 13 - no records week Jul 20 - no records week Jul 27 - 2 records Week Aug 3 - no records Week Aug 10 - 2 records Week Aug 17 - no records And pass Jul 12 date should return true, if I pass jul 15 should return false
I had to see your sample data set from your last question along with explanation from your last question as well as the explanation given in this question to come up with this solution.
When you ask a question here put yourself in the reader's shoes and see if the question makes any sense, anyway I hope this solution will get you what you want. cheers
CREATE PROCEDURE get_output
#Date DATE
,#ID INT
,#Output INT OUTPUT -- 1 true , 0 false
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Count INT;
SELECT #Count = COUNT(*)
FROM TableName
WHERE CAST(DATEADD(WEEK, DATEDIFF(WEEK, 0, #Date), 0) AS DATE)
= CAST(DATEADD(WEEK, DATEDIFF(WEEK, 0, [Date]), 0) AS DATE)
AND ID = #ID
GROUP BY CAST(DATEADD(WEEK, DATEDIFF(WEEK, 0, [Date]), 0) AS DATE)
IF (#Count < 2)
SET #Output = 1;
ELSE
SET #Output = 0;
END

Get first day of week in SQL Server

I am trying to group records by week, storing the aggregated date as the first day of the week. However, the standard technique I use for rounding off dates does not appear to work correctly with weeks (though it does for days, months, years, quarters and any other timeframe I've applied it to).
Here is the SQL:
select "start_of_week" = dateadd(week, datediff(week, 0, getdate()), 0);
This returns 2011-08-22 00:00:00.000, which is a Monday, not a Sunday. Selecting ##datefirst returns 7, which is the code for Sunday, so the server is setup correctly in as far as I know.
I can bypass this easily enough by changing the above code to:
select "start_of_week" = dateadd(week, datediff(week, 0, getdate()), -1);
But the fact that I have to make such an exception makes me a little uneasy. Also, apologies if this is a duplicate question. I found some related questions but none that addressed this aspect specifically.
To answer why you're getting a Monday and not a Sunday:
You're adding a number of weeks to the date 0. What is date 0? 1900-01-01. What was the day on 1900-01-01? Monday. So in your code you're saying, how many weeks have passed since Monday, January 1, 1900? Let's call that [n]. Ok, now add [n] weeks to Monday, January 1, 1900. You should not be surprised that this ends up being a Monday. DATEADD has no idea that you want to add weeks but only until you get to a Sunday, it's just adding 7 days, then adding 7 more days, ... just like DATEDIFF only recognizes boundaries that have been crossed. For example, these both return 1, even though some folks complain that there should be some sensible logic built in to round up or down:
SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');
To answer how to get a Sunday:
If you want a Sunday, then pick a base date that's not a Monday but rather a Sunday. For example:
DECLARE #dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, #dt, CURRENT_TIMESTAMP), #dt);
This will not break if you change your DATEFIRST setting (or your code is running for a user with a different setting) - provided that you still want a Sunday regardless of the current setting. If you want those two answers to jive, then you should use a function that does depend on the DATEFIRST setting, e.g.
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
So if you change your DATEFIRST setting to Monday, Tuesday, what have you, the behavior will change. Depending on which behavior you want, you could use one of these functions:
CREATE FUNCTION dbo.StartOfWeek1 -- always a Sunday
(
#d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', #d), '19050101'));
END
GO
...or...
CREATE FUNCTION dbo.StartOfWeek2 -- always the DATEFIRST weekday
(
#d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, #d), #d));
END
GO
Now, you have plenty of alternatives, but which one performs best? I'd be surprised if there would be any major differences but I collected all the answers provided so far and ran them through two sets of tests - one cheap and one expensive. I measured client statistics because I don't see I/O or memory playing a part in the performance here (though those may come into play depending on how the function is used). In my tests the results are:
"Cheap" assignment query:
Function - client processing time / wait time on server replies / total exec time
Gandarez - 330/2029/2359 - 0:23.6
me datefirst - 329/2123/2452 - 0:24.5
me Sunday - 357/2158/2515 - 0:25.2
trailmax - 364/2160/2524 - 0:25.2
Curt - 424/2202/2626 - 0:26.3
"Expensive" assignment query:
Function - client processing time / wait time on server replies / total exec time
Curt - 1003/134158/135054 - 2:15
Gandarez - 957/142919/143876 - 2:24
me Sunday - 932/166817/165885 - 2:47
me datefirst - 939/171698/172637 - 2:53
trailmax - 958/173174/174132 - 2:54
I can relay the details of my tests if desired - stopping here as this is already getting quite long-winded. I was a bit surprised to see Curt's come out as the fastest at the high end, given the number of calculations and inline code. Maybe I'll run some more thorough tests and blog about it... if you guys don't have any objections to me publishing your functions elsewhere.
For these that need to get:
Monday = 1 and Sunday = 7:
SELECT 1 + ((5 + DATEPART(dw, GETDATE()) + ##DATEFIRST) % 7);
Sunday = 1 and Saturday = 7:
SELECT 1 + ((6 + DATEPART(dw, GETDATE()) + ##DATEFIRST) % 7);
Above there was a similar example, but thanks to double "%7" it would be much slower.
For those who need the answer at work and creating function is forbidden by your DBA, the following solution will work:
select *,
cast(DATEADD(day, -1*(DATEPART(WEEKDAY, YouDate)-1), YourDate) as DATE) as WeekStart
From.....
This gives the start of that week. Here I assume that Sundays are the start of weeks. If you think that Monday is the start, you should use:
select *,
cast(DATEADD(day, -1*(DATEPART(WEEKDAY, YouDate)-2), YourDate) as DATE) as WeekStart
From.....
This works wonderfully for me:
CREATE FUNCTION [dbo].[StartOfWeek]
(
#INPUTDATE DATETIME
)
RETURNS DATETIME
AS
BEGIN
-- THIS does not work in function.
-- SET DATEFIRST 1 -- set monday to be the first day of week.
DECLARE #DOW INT -- to store day of week
SET #INPUTDATE = CONVERT(VARCHAR(10), #INPUTDATE, 111)
SET #DOW = DATEPART(DW, #INPUTDATE)
-- Magic convertion of monday to 1, tuesday to 2, etc.
-- irrespect what SQL server thinks about start of the week.
-- But here we have sunday marked as 0, but we fix this later.
SET #DOW = (#DOW + ##DATEFIRST - 1) %7
IF #DOW = 0 SET #DOW = 7 -- fix for sunday
RETURN DATEADD(DD, 1 - #DOW,#INPUTDATE)
END
Maybe you need this:
SELECT DATEADD(DD, 1 - DATEPART(DW, GETDATE()), GETDATE())
Or
DECLARE #MYDATE DATETIME
SET #MYDATE = '2011-08-23'
SELECT DATEADD(DD, 1 - DATEPART(DW, #MYDATE), #MYDATE)
Function
CREATE FUNCTION [dbo].[GetFirstDayOfWeek]
( #pInputDate DATETIME )
RETURNS DATETIME
BEGIN
SET #pInputDate = CONVERT(VARCHAR(10), #pInputDate, 111)
RETURN DATEADD(DD, 1 - DATEPART(DW, #pInputDate),
#pInputDate)
END
GO
Googled this script:
create function dbo.F_START_OF_WEEK
(
#DATE datetime,
-- Sun = 1, Mon = 2, Tue = 3, Wed = 4
-- Thu = 5, Fri = 6, Sat = 7
-- Default to Sunday
#WEEK_START_DAY int = 1
)
/*
Find the fisrt date on or before #DATE that matches
day of week of #WEEK_START_DAY.
*/
returns datetime
as
begin
declare #START_OF_WEEK_DATE datetime
declare #FIRST_BOW datetime
-- Check for valid day of week
if #WEEK_START_DAY between 1 and 7
begin
-- Find first day on or after 1753/1/1 (-53690)
-- matching day of week of #WEEK_START_DAY
-- 1753/1/1 is earliest possible SQL Server date.
select #FIRST_BOW = convert(datetime,-53690+((#WEEK_START_DAY+5)%7))
-- Verify beginning of week not before 1753/1/1
if #DATE >= #FIRST_BOW
begin
select #START_OF_WEEK_DATE =
dateadd(dd,(datediff(dd,#FIRST_BOW,#DATE)/7)*7,#FIRST_BOW)
end
end
return #START_OF_WEEK_DATE
end
go
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=47307
CREATE FUNCTION dbo.fnFirstWorkingDayOfTheWeek
(
#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)
DECLARE #wd int = 1+(((#dow+#ds) % 7)+5) % 7 -- this is always return Mon as 1,Tue as 2 ... Sun as 7
RETURN DATEADD(dd,1-#wd,#currentDate)
END
For the basic (the current week's Sunday)
select cast(dateadd(day,-(datepart(dw,getdate())-1),getdate()) as date)
If previous week:
select cast(dateadd(day,-(datepart(dw,getdate())-1),getdate()) -7 as date)
Internally, we built a function that does it but if you need quick and dirty, this will do it.
Since Julian date 0 is a Monday just add the number of weeks to Sunday
which is the day before -1 Eg. select dateadd(wk,datediff(wk,0,getdate()),-1)
I found some of the other answers long-winded or didn't actually work if you wanted Monday as the start of the week.
Sunday
SELECT DATEADD(week, DATEDIFF(week, -1, GETDATE()), -1) AS Sunday;
Monday
SELECT DATEADD(week, DATEDIFF(week, 0, GETDATE() - 1), 0) AS Monday;
Set DateFirst 1;
Select
Datepart(wk, TimeByDay) [Week]
,Dateadd(d,
CASE
WHEN Datepart(dw, TimeByDay) = 1 then 0
WHEN Datepart(dw, TimeByDay) = 2 then -1
WHEN Datepart(dw, TimeByDay) = 3 then -2
WHEN Datepart(dw, TimeByDay) = 4 then -3
WHEN Datepart(dw, TimeByDay) = 5 then -4
WHEN Datepart(dw, TimeByDay) = 6 then -5
WHEN Datepart(dw, TimeByDay) = 7 then -6
END
, TimeByDay) as StartOfWeek
from TimeByDay_Tbl
This is my logic. Set the first of the week to be Monday then calculate what is the day of the week a give day is, then using DateAdd and Case I calculate what the date would have been on the previous Monday of that week.
This is a useful function for me
/* MeRrais 211126
select [dbo].[SinceWeeks](0,NULL)
select [dbo].[SinceWeeks](5,'2021-08-31')
*/
alter Function [dbo].[SinceWeeks](#Weeks int, #From datetime=NULL)
Returns date
AS
Begin
if #From is null
set #From=getdate()
return cast(dateadd(day, -(#Weeks*7+datepart(dw,#From)-1), #From) as date)
END
I don't have any issues with any of the answers given here, however I do think mine is a lot simpler to implement, and understand. I have not run any performance tests on it, but it should be neglegable.
So I derived my answer from the fact that dates are stored in SQL server as integers, (I am talking about the date component only). If you don't believe me, try this SELECT CONVERT(INT, GETDATE()), and vice versa.
Now knowing this, you can do some cool math equations. You might be able to come up with a better one, but here is mine.
/*
TAKEN FROM http://msdn.microsoft.com/en-us/library/ms181598.aspx
First day of the week is
1 -- Monday
2 -- Tuesday
3 -- Wednesday
4 -- Thursday
5 -- Friday
6 -- Saturday
7 (default, U.S. English) -- Sunday
*/
--Offset is required to compensate for the fact that my ##DATEFIRST setting is 7, the default.
DECLARE #offSet int, #testDate datetime
SELECT #offSet = 1, #testDate = GETDATE()
SELECT CONVERT(DATETIME, CONVERT(INT, #testDate) - (DATEPART(WEEKDAY, #testDate) - #offSet))
I had a similar problem. Given a date, I wanted to get the date of the Monday of that week.
I used the following logic: Find the day number in the week in the range of 0-6, then subtract that from the originay date.
I used: DATEADD(day,-(DATEPART(weekday,)+5)%7,)
Since DATEPRRT(weekday,) returns 1 = Sundaye ... 7=Saturday,
DATEPART(weekday,)+5)%7 returns 0=Monday ... 6=Sunday.
Subtracting this number of days from the original date gives the previous Monday. The same technique could be used for any starting day of the week.
I found this simple and usefull. Works even if first day of week is Sunday or Monday.
DECLARE #BaseDate AS Date
SET #BaseDate = GETDATE()
DECLARE #FisrtDOW AS Date
SELECT #FirstDOW = DATEADD(d,DATEPART(WEEKDAY,#BaseDate) *-1 + 1, #BaseDate)
Maybe I'm over simplifying here, and that may be the case, but this seems to work for me. Haven't ran into any problems with it yet...
CAST('1/1/' + CAST(YEAR(GETDATE()) AS VARCHAR(30)) AS DATETIME) + (DATEPART(wk, YOUR_DATE) * 7 - 7) as 'FirstDayOfWeek'
CAST('1/1/' + CAST(YEAR(GETDATE()) AS VARCHAR(30)) AS DATETIME) + (DATEPART(wk, YOUR_DATE) * 7) as 'LastDayOfWeek'

Resources