To answer why you get Monday instead of Sunday:
You add a few weeks to date 0. What is date 0? 1900-01-01. What was the day 1900-01-01? Monday. So, in the code you say, how many weeks have passed since Monday, January 1, 1900? Let me call it [n]. Ok, now add [n] weeks on Monday, January 1, 1900. Do not be surprised that it ends on Monday. DATEADD has no idea that you want to add a few weeks, but only until you get to Sunday, just add 7 days, then add another 7 days ... just like DATEDIFF only recognizes borders that have been crossed. For example, they return 1, although some people complain that there must be some reasonable logic 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 Sunday:
If you want Sundays, select a base date, not Monday, but rather Sunday. For example:
DECLARE @dt DATE = '1905-01-01'; SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);
This will not be broken if you change the DATEFIRST setting (or your code will be run for the user with a different setting) - provided that you still want Sunday, regardless of the current setting. If you want these two answers to be jive, then you should use a function that depends on the DATEFIRST parameter, for example.
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
So, if you change your DATEFIRST parameter to Monday, Tuesday, what you have, the behavior will change. Depending on what behavior you want, you can use one of the following 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
You now have many alternatives, but which one works best? I would be surprised if there were any significant differences, but I collected all the answers provided so far and conducted them through two sets of tests - one cheap and one expensive. I measured client statistics because I donβt see I / O or memory play a role in performance here (although they may go into the game depending on how the function is used). In my tests, the results are:
"Cheap" job request:
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
Dear assignment request:
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, if desired, pass on the details of my tests - stopping here, as this is already quite long. I was a little surprised to see that Kurt came out as the fastest at the top end, given the amount of computation and the built-in code. Perhaps I will conduct more detailed tests and a blog about this ... if you have no objection to posting your functions elsewhere.