SET DATEFIST = 1 not working correctly - sql-server

I'm having trouble to make SET DATEFIRST to work properly on some simple queries I working on at the moment.
Here is my first example:
SET DATEFIRST = 1
SELECT count(Distinct ID)
FROM Products
WHERE
Location in (12)
and YEAR (CREATED) = '2018'
Group by datepart(wk, created), year(created)
The above code gives me some results correct and some others wrong. It's basically counting from Monday to Monday, but I want it to count from Monday to Sunday. I still don't understand why it's counting 8 days instead of 7 days on some of the weeks.
Also I have multiple selections with SET DATEFIRST = 1 which also doesn't work:
SET DATEFIRST = 1
--Products finished this week
SELECT count(Distinct ID)
FROM Products
WHERE
Created >= dateadd(day, 1-datepart(dw, getdate()), CONVERT(date,getdate()))
AND Created < dateadd(day, 8-datepart(dw, getdate()), CONVERT(date,getdate()))
AND Location in (15,16,17) AND (Location IS NOT NULL OR Location NOT IN(18))
UNION ALL
--------------------------------------------
-- Products received this week
SELECT count(Distinct ID)
FROM Products
WHERE
Created >= dateadd(day, 1-datepart(dw, getdate()), CONVERT(date,getdate()))
AND Created < DATEADD(DAY,0,DATEDIFF(DAY,0,dateadd(day, 8-datepart(dw, getdate()),getdate())))
AND Location in(1)
The above code is not reacting to SET DATEFIRST = 1
It's not counting from Monday to sunday, instead it's counting from Sunday to sunday (8 days)

Here is your issue:
DATEADD(day, 8-datepart(DW, GETDATE()), CONVERT(DATE,GETDATE())))
You are comparing a DATETIME from the database with a TIME to a DATE with no TIME. So the DATE portions on next Monday will be equal and your < will fail.
This will not work because the DB field is a DATETIME and you are comparing to a DATE.
SET #D= '06/25/2018 01:20:23 AM' --Monday next week with a time
IF(#D < DATEADD(day, 8-datepart(DW, GETDATE()), CONVERT(GETDATE()))) --<--The whole day
SELECT 1 -- '06/25/2018 12:00:23 AM' < (DATE)2018-06-25
ELSE
SELECT 2
Returns 2
If you do want to include everything through Sunday then you need to set the cutoff to 12:00:00 AM Monday morning. One way to do that would be something like:
DATEADD(DAY,0,DATEDIFF(DAY,0,dateadd(day, 8-datepart(dw, getdate()),getdate())))

Related

How to find the past 4 weeks of the same weekday value starting today

I am trying to select records from today and the same day of each week for the last 4 weeks.
Today (Tuesday)
Last Tuesday
The Tuesday before that
The Tuesday before that
I need this to be tied to current date because I am going to run this query every day so I don't want to use a between or something where I manually specify the date range.
Everything I have found or tried so far has pulled the last month of data but not the last 4 weeks of the same weekday.
select *
from table
where thedatecolumn >= DATEADD(mm, -1, GETDATE())
This works but pulls everything from the last month.
If today's date is 7/10/2019 I need
Data from 7/10/2019
Data from 7/3/2019
Data from 6/26/2019
Data from 6/19/2019
Every day I will run this query, so I need it to be dynamic based on the current date.
I believe you want to look back 21 days and then filter those dates that have the same day of week:
select * from table
where thedatecolumn >= DATEADD(DAY, -21, CAST(GETDATE() AS DATE))
and DATEPART(WEEKDAY, thedatecolumn) = DATEPART(WEEKDAY, GETDATE())
You Can try using a recursive cte which starts today and repeatedly substracts 7 days - so you ensure you always land on the same weekday. Following an example:
WITH cteFromToday AS(
SELECT 0 AS WeeksBack, GETDATE() AS MyDate
UNION ALL
SELECT WeeksBack + 1 AS WeeksBack, DATEADD(d, -7, MyDate) AS MyDate
FROM cteFromToday
)
SELECT TOP 5 *
FROM cteFromToday
OPTION ( MaxRecursion 0 );
This is quite simple. Substitute CURRENT_TIMESTAMP here for any given date.
SELECT CONVERT(DATE,CURRENT_TIMESTAMP) AS Today,
DATEADD(DAY,-7,CONVERT(DATE,CURRENT_TIMESTAMP)) AS LastWeek ,
DATEADD(DAY,-14,CONVERT(DATE,CURRENT_TIMESTAMP)) AS TwoWeeksAgo,
DATEADD(DAY,-21,CONVERT(DATE,CURRENT_TIMESTAMP)) AS ThreeWeeksAgo
SO, if you want to get data for a set of ranges for one entire day with those dates:
SELECT something
WHERE
datetimecolumn >= CONVERT(DATE,CURRENT_TIMESTAMP) AND datetimecolumn < DATEADD(DAY,1, CONVERT(DATE,CURRENT_TIMESTAMP)) -- Todays range,
OR datetimecolumn >= DATEADD(DAY,-7,CONVERT(DATE,CURRENT_TIMESTAMP)) AND datetimecolumn < DATEADD(DAY,1,DATEADD(DAY,-7,CONVERT(DATE,CURRENT_TIMESTAMP)))-- LastWeek ,
OR datetimecolumn >= DATEADD(DAY,-14,CONVERT(DATE,CURRENT_TIMESTAMP)) AND datetimecolumn < DATEADD(DAY,1,DATEADD(DAY,-14,CONVERT(DATE,CURRENT_TIMESTAMP)))-- TwoWeeksAgo,
OR datetimecolumn >= DATEADD(DAY,-21,CONVERT(DATE,CURRENT_TIMESTAMP)) AND datetimecolumn < DATEADD(DAY,1, DATEADD(DAY,-21,CONVERT(DATE,CURRENT_TIMESTAMP))) -- ThreeWeeksAgo

SQL : If first day of the new month then run report for previous month

I have some reports which run showing data MTD
Here is the code that is not working how I would like
StartDate = select dateadd(s,0,dateadd(mm, datediff(m,0,getdate()),0))
EndDate = getdate()
Our data replication happens at the end of each day.
So on the First day of each month I don't want a blank report to run.
what I would like to happen.
Only If its the first day of the month then the StartDate must be beginning of last month and EndDate to be end of last month. Else use
StartDate = select dateadd(s,0,dateadd(mm, datediff(m,0,getdate()),0)) and
EndDate = getdate()
Not exactly sure about your main query. This is how you could get first and last day of last month depending on the given date being 1st of current month.
Please note, else part of each case expression setting the current date for both first and last date. You can set them as null if needed.
DECLARE #Today DATETIME = GETDATE()
DECLARE #FirsDay DATETIME = CASE WHEN DATEPART(DAY, #Today) = 1
THEN DATEADD(MONTH, -1, #Today) --first day of last month
ELSE #Today END --current date for other dates
DECLARE #LastDay DATETIME = CASE WHEN DATEPART(DAY, #Today) = 1
THEN DATEADD(DAY, -1, #Today) --last date of last month
ELSE #Today END --current date for other dates
Thanks all.
so the rabbit hole got a bit deeper
Example : What about when the 1st falls on a Saturday ?
I need it to run using the last trading day if its the first day of the new month.
what I ended up using was a function that uses our working hours table
ALTER FUNCTION [data].[Last_Trade_Day] (#Date date)
returns date as
begin
declare #OrigDate date = isnull(#Date, getdate())
return (
select max(convert(date, wh_starttime))
from Embrace.fact.Working_Hours
where convert(date, wh_starttime) < #OrigDate
)
end
The code in the report now look's like :
declare #EndDate date = Embrace.data.Last_Trade_Day(isnull(#Date, getdate()))
declare #StartDate date = dateadd(mm, 0, dateadd(mm, datediff(m, 0, #EndDate), 0))
You can try to use something like this:
-- Create demo data
CREATE TABLE #dates(get_date_simulation datetime)
INSERT INTO #dates(get_date_simulation)
VALUES (N'2015-07-01 13:46:47.063'), -- fallback to 2015-06-01
(N'2015-07-02 13:46:47.063') -- use this date normal
-- Your part
SELECT get_date_simulation,
CASE
WHEN DATEPART(day,get_date_simulation) = 1
THEN DATEADD(month,-1,DATEADD(day,(DATEPART(day,get_date_simulation)-1)*-1,get_date_simulation))
ELSE DATEADD(day,(DATEPART(day,get_date_simulation)-1)*-1, get_date_simulation)
END as start_date,
CASE
WHEN DATEPART(day,get_date_simulation) = 1
THEN DATEADD(second,-1,CONVERT(datetime,CONVERT(date,get_date_simulation)))
ELSE get_date_simulation
END as end_date
FROM #dates
-- Cleanup
DROP TABLE #dates
Which results into this:
get_date_simulation start_date end_date
----------------------- ----------------------- -----------------------
2015-07-01 13:46:47.063 2015-06-01 13:46:47.063 2015-06-30 23:59:59.000
2015-07-02 13:46:47.063 2015-07-01 13:46:47.063 2015-07-02 13:46:47.063
To me it seems as simple as subtracting 1 day from the current date to get the start date
SELECT StartDate =
DATEADD(s,0,DATEADD(mm,DATEDIFF(m,0,GETDATE() - 1),0))
Then you just get the end date using the current date without the time
SELECT EndDate =
CONVERT(DATE, GETDATE()
Then your query is WHERE date >= StartDate and < EndDate

SQL Server - Finding the first day of the week

I've been looking around for a chunk of code to find the first day of the current week, and everywhere I look I see this:
DATEADD(WK, DATEDIFF(WK,0,GETDATE()),0)
Every place says this is the code I'm looking for.
The problem with this piece of code is that if you run it for Sunday it chooses the following Monday.
If I run:
SELECT GetDate() , DATEADD(WK, DATEDIFF(WK,0,GETDATE()),0)
Results for today (Tuesday):
2013-05-14 09:36:39.650................2013-05-13 00:00:00.000
This is correct, it chooses Monday the 13th.
If I run:
SELECT GetDate()-1 , DATEADD(WK, DATEDIFF(WK,0,GETDATE()-1),0)
Results for yesterday (Monday):
2013-05-13 09:38:57.950................2013-05-13 00:00:00.000
This is correct, it chooses Monday the 13th.
If I run:
SELECT GetDate()-2 , DATEADD(WK, DATEDIFF(WK,0,GETDATE()-2),0)
Results for the 12th (Sunday):
2013-05-12 09:40:14.817................2013-05-13 00:00:00.000
This is NOT correct, it chooses Monday the 13th when it should choose the previous Monday, the 6th.
Can anyone illuminate me as to what's going in here? I find it hard to believe that no one has pointed out that this doesn't work, so I'm wondering what I'm missing.
It is DATEDIFF that returns the "incorrect" difference of weeks, which in the end results in the wrong Monday. And that is because DATEDIFF(WEEK, ...) doesn't respect the DATEFIRST setting, which I'm assuming you have set to 1 (Monday), and instead always considers the week crossing to be from Saturday to Sunday, or, in other words, it unconditionally considers Sunday to be the first day of the week in this context.
As for an explanation for that, so far I haven't been able to find an official one, but I believe this must have something to do with the DATEDIFF function being one of those SQL Server treats as always deterministic. Apparently, if DATEDIFF(WEEK, ...) relied on the DATEFIRST, it could no longer be considered always deterministic, which I can only guess wasn't how the developers of SQL Server wanted it.
To find the first day of the week's date, I would (and most often do actually) use the first suggestion in #Jasmina Shevchenko's answer:
DATEADD(DAY, 1 - DATEPART(WEEKDAY, #Date), #Date)
DATEPART does respect the DATEFIRST setting and (most likely as a result) it is absent from the list of always deterministic functions.
Try this one -
SET DATEFIRST 1
DECLARE #Date DATETIME
SELECT #Date = GETDATE()
SELECT CAST(DATEADD(DAY, 1 - DATEPART(WEEKDAY, #Date), #Date) AS DATE)
SELECT CAST(#Date - 2 AS DATE), CAST(DATEADD(WK, DATEDIFF(WK, 0, #Date-2), 0) AS DATE)
Results:
---------- ----------
2013-05-12 2013-05-13
SQL Server has a SET DATEFIRST function which allows you to tell it what the first day of the week should be. SET DATEFIRST = 1 tells it to consider Monday as the first day of the week. You should check what the server's default setting is via ##DATEFIRST. Or you could simply change it at the start of your query.
Some references:
MSDN
Similar Question
That worked for me like a charm:
Setting moday as first day of the week without changing DATEFIRST variable:
-- FirstDayWeek
select dateadd(dd,(datepart(dw, case datepart(dw, [yourDate]) when 1 then dateadd(dd,-1,[yourDate]) else [yourDate] end) * -1) + 2, case datepart(dw, [yourDate]) when 1 then dateadd(dd,-1,[yourDate]) else [yourDate] end) as FirstDayWeek;
-- LastDayWeek
select dateadd(dd, (case datepart(dw, [yourDate]) when 1 then datepart(dw, dateadd(dd,-1,[yourDate])) else datepart(dw, [yourDate]) end * -1) + 8, case datepart(dw, [yourDate]) when 1 then dateadd(dd,-1,[yourDate]) else [yourDate] end) as LastDayWeek;
Setting sunday as fist day of the week without changing DATEFIRST variable
select convert(varchar(50), dateadd(dd, (datepart(dw, [yourDate]) * -1) + 2, [yourDate]), 103) as FirstDayWeek, convert(varchar(50), dateadd(dd, (datepart(dw, [yourDate]) * -1) + 8, [yourDate]), 103) as LastDayWeek;
You can change [yourDate] by GETDATE() for testing

How do I find a future date based upon the corresponding weekday?

I am developing a calendaring system whereby events are created. I need to be able to "roll forward" any event (which occurs on a single day) to a user-specified month/year.
For example, March 4, 2013 is a Monday. I need to be able to determine, by the given month/year, what the corresponding date would be - based upon the weekday and its position within the month. So, in this example the corresponding date for April would be April 1, which is a Monday.
Another example: March 13, 2013 is a Wednesday, so the corresponding date in May would be May 8.
If it were not for the fact that user supplied month/year is variable, this would not be so difficult a task; but since it is...
If you had a Dates table containing five columns, FullDate, Month, Day, Year, and DayOfWeek, and populated with dates well into the future you could easily do the following.
Assuming #m and #y are the user-specified month/year to roll forward to, and #d is the event date:
DECLARE #weekNumInMonth int =
(
SELECT COUNT(1)
FROM Dates
WHERE Year = datepart(year #d)
AND Month = datepart(month, #d)
AND DayOfWeek = datepart(weekday, #d)
AND Day <= datepart(day, #d)
)
SELECT MAX(FullDate)
FROM
(
SELECT TOP #weekNumInMonth
FROM Dates
WHERE Year = #y
AND Month = #m
AND DayOfWeek = datepart(weekday, #d)
) x
Without a dates table, you'll just have to do some math:
DECLARE #DOW int = datepart(weekday, #d)
DECLARE #firstDayInMonth date = dateadd(day, 1-datepart(day, #d), #d)
DECLARE #firstDayInMonthDOW int = datepart(weekday, #firstDayInMonth)
DECLARE #firstSameDayInMonth date =
dateadd(day, (7-(#firstDayInMonthDOW-#DOW))%7, #firstDayInMonth)
DECLARE #weekInMonth int = datediff(week, #firstSameDayInMonth, #d)
DECLARE #corr date = datefromparts(#y, #m, 1)
DECLARE #corrDOW int = datepart(weekday, #corr)
DECLARE #corrFirstSameDay date = dateadd(day, (7-(#corrDOW-#DOW))%7, #corr)
SELECT dateadd(week, #weekInMonth, #corrFirstSameDay)
SQL Fiddle example
It's a little ugly, but what it does is:
Get the first day of the month with the same weekday as #d into #firstSameDayInMonth.
Figure out which week # #d is in within its corresponding month, as a 0-based integer #weekInMonth. This is the number of weeks between #firstSameDayInMonth and #d.
Get the first day of month #m, year #y with the same weekday as #d into #corrFirstSameDay.
Add the 0-based number of weeks #weekInMonth to #corrFirstSameDay to get the result.
Can you do it as a one-liner? Sure, just substitute your variables. Be warned though, it's ugly, and there's really nothing to be gained from it except lack of readability IMHO:
SELECT dateadd(week, datediff(week, dateadd(day, (7-(datepart(weekday, dateadd(day,
1-datepart(day, #d), #d))-datepart(weekday, #d)))%7, dateadd(day,
1-datepart(day, #d), #d)), #d), dateadd(day, (7-(datepart(weekday,
datefromparts(#y, #m, 1))-datepart(weekday, #d)))%7, datefromparts(#y, #m, 1)))

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