How to get date if we have fiscal week - sql

I have stored fiscal week in my table as Nvarchar(Max)
CREATE TABLE sample(
id int
,FiscalWeekName NvarChar(MAX)
);
INSERT INTO sample VALUES(1,'FY15-W1');
No, I want to convert this fiscalweekname into the first day of that week
For example query should return
01-01-2014

I don't even know how you define fiscal weeks but here's a stab:
dateadd(
week,
cast(substring(FiscalWeekName, 7, 2) as int) - 1,
dateadd(year, -1, cast('20' + substring(FiscalWeekName, 3, 2) + '0101' as date))
)
A numeric year by itself will cast to January 1 but it's probably safer not to rely on that so I added the '0101'.
EDIT: After your clarification I'm trying to adjust the day of week to slide back to Monday (and I'm assuming that's what your DATEFIRST setting is as well.) This seems messy so maybe there's a cleaner way.
dateadd(
day,
(cast(substring(FiscalWeekName, 7, 2) as int) - 1) * 7
- case
when cast(substring(FiscalWeekName, 7, 2) as int) > 1
then
datepart(
dw,
dateadd(
year,
-1,
cast('20' + substring(FiscalWeekName, 3, 2) + '0101' as date)
)
)
else 0
end,
dateadd(year, -1, cast('20' + substring(FiscalWeekName, 3, 2) + '0101' as date))
)

Please try this, correction from #shawnt00
declare #FiscalWeekName as NvarChar(MAX)
set #FiscalWeekName = 'FY15-W2'
SELECT cast(substring(#FiscalWeekName, charindex('W', #FiscalWeekName) + 1, 2) as int), dateadd(
wk,
cast(substring(#FiscalWeekName, charindex('W', #FiscalWeekName) + 1, 2) as int)
,dateadd(yy, -1, cast('20'+substring(#FiscalWeekName, 3, 2)+'0101' as date))
)

Below solution will give you the first day/date of week as per Fiscal+Week,
declare #FiscalWeekName as NvarChar(MAX)
set #FiscalWeekName = 'FY15-W5'
DECLARE #FiscalYear as datetime
set #FiscalYear = dateadd(
WEEK,
cast(substring(#FiscalWeekName, charindex('W', #FiscalWeekName) + 1, 2) as int) -1
,dateadd(yy, -1, cast('20'+substring(#FiscalWeekName, 3, 2)+'0101 01:01:01.1111111' as date))
)
SELECT DATEADD(dd, -(DATEPART(dw, #FiscalYear)-1), #FiscalYear) as FiscalYear

Related

SQL server Retrieve week start date and week end date from week number and year

I need to retrieve the start and the end date of a year's week.
This is my input:
YEAR = 2019 WEEK = 32
The result will be: 05/08/2019 and 11/08/2019.
I tried this:
select (dateadd(week,32-(1),dateadd(week,datediff(week,(-1),dateadd(year,datediff(year,(0),getdate()),(0))),(0))))
select (dateadd(week,32+datediff(week,(0),dateadd(year,datediff(year,(0),getdate()),(0))),(-1)))
but there is no year input, so it will work only for the current year
I need to put this function, into a calculated fields, creating table
One possible option is the following statement:
DECLARE #year int = 2019
DECLARE #week int = 32
DECLARE #date date
SELECT #date = DATEADD(week, (#week - 1), DATEFROMPARTS(#year, 1, 1))
SELECT
#date AS CurrentDay,
DATEADD(day, - DATEPART(weekday, #date) + 1, #date) AS StartOfTheWeek,
DATEADD(day, 7 - DATEPART(weekday, #date), #date) AS EndOfTheWeek
Result:
CurrentDay StartOfTheWeek EndOfTheWeek
2019-08-06 2019-08-05 2019-08-11
If you want to define a table with calculated columns:
CREATE TABLE Data (
[Year] int,
[Week] int,
[Start_Date] AS DATEADD (
day,
- DATEPART(weekday, DATEADD(week, ([Week] - 1), DATEFROMPARTS([Year], 1, 1))) + 1,
DATEADD(week, ([Week] - 1), DATEFROMPARTS([Year], 1, 1))
),
[End_Date] AS DATEADD (
day,
7 - DATEPART(weekday, DATEADD(week, ([Week] - 1), DATEFROMPARTS([Year], 1, 1))),
DATEADD(week, ([Week] - 1), DATEFROMPARTS([Year], 1, 1))
)
)
INSERT INTO Data ([Year], [Week])
VALUES (2019, 32)
This can be achieved with STR_TO_DATE: http://www.java2s.com/Tutorial/MySQL/0280__Date-Time-Functions/Toconvertayearweektoadatethenyoushouldalsospecifytheweekday.htm

How to get the last sunday of the year using TSQL?

I need to check if a given day is the last sunday of any year, if yes the return 1 using TSQL only.
I do not have much idea about TSQL.
SQL Server has a problem with weekdays, because they can be affected by internationalization settings. Assuming the defaults, you can do:
select dateadd(day,
1 - datepart(weekday, datefromparts(#year, 12, 31)),
datefromparts(#year, 12, 31)
)
Otherwise, you'll need to do a case expression to turn the day of the week into a number.
In an older version of SQL Server, you could do:
select dateadd(day,
1 - datepart(weekday, cast(#year + '0101' as date)),
cast(#year + '0101' as date)
)
I haven't worked with tsql specifically but if my sql knowledge and googling is good enough then something like this should do the trick:
... WHERE DATEPART(dw, date) = 7 and DATEDIFF (d, date, DATEFROMPARTS (DATEPART(yyyy, date), 12, 31)) <= 6
Basically we check if that day is Sunday at first and then if it's less than week away from last day of the year
Using Mr. Gordon's query, following IIF() returns 1 if given day is last Sunday of the year, returns 0 if it is not.
Using 2018 as year and 2018-12-30 as given date. You can replace values with variables.
select IIF( DATEDIFF(DAY,'2018-12-30',
DATEADD(day,
1 - datepart(weekday, datefromparts(2018, 12, 31)),
datefromparts(2018, 12, 31)
)) = 0, 1, 0)
You can use this function
Function Code :
create FUNCTION CheckIsSaturday
(
#date DATETIME
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE #result INT
DECLARE #DayOfWeek NVARCHAR(22)
DECLARE #LastDayOfYear DATETIME
select #LastDayOfYear=DATEADD(yy, DATEDIFF(yy, 0, #date) + 1, -1)
SELECT #DayOfWeek=DATENAME(dw, #date)
IF(#DayOfWeek='Saturday' AND DATEDIFF(dd,#date,#LastDayOfYear)<7)
RETURN 1;
RETURN 0;
END
GO
function Usage:
SELECT dbo.CheckIsSaturday('2017-12-23')
This becomes quite trivial if you have a Calendar Table
DECLARE #CheckDate DATE = '20181230'
;WITH cteGetDates AS
(
SELECT
[Date], WeekDayName, WeekOfMonth, [MonthName], [Year]
,LastDOWInMonth = ROW_NUMBER() OVER
(
PARTITION BY FirstDayOfMonth, [Weekday]
ORDER BY [Date] DESC
)
FROM
dbo.DateDimension
)
SELECT * FROM cteGetDates D
WHERE D.LastDOWInMonth = 1 AND D.WeekDayName = 'Sunday' and D.MonthName = 'December' AND D.[Date] = #CheckDate
You can also use this one to get every last day of the year:
;WITH getlastdaysofyear ( LastDay, DayCnt ) AS (
SELECT DATEADD(dd, -DAY(DATEADD(mm, 1, DATEADD(yy, DATEDIFF(yy, 0, GETDATE()) + 1, -1))),
DATEADD(mm, 1, DATEADD(yy, DATEDIFF(yy, 0, GETDATE()) + 1, -1))),
0 AS DayCnt
UNION ALL
SELECT LastDay,
DayCnt + 1
FROM getlastdaysofyear
)
SELECT *
FROM ( SELECT TOP 7 DATEADD(DD, -DayCnt, LastDay) LastDate,
'Last ' + DATENAME(Weekday,DATEADD(DD, -DayCnt, LastDay)) AS DayStatus
FROM getlastdaysofyear ) T
ORDER BY DATEPART(Weekday, LastDate)
Hope you like it :)

Finding week start and week end date

I have a week number and year and i need to display "total for mm/dd/yy to mm/dd/yy in a row of my ssrs report. My week starts with Monday. For example if my week number is '2' and year is '2010' then I have to display "total for 01/04/2010 to 01/10/2010 in my ssrs column. how to do this?
Try this
declare #year char(4) = '2010'
declare #week int = 2
declare #fromdate datetime
declare #todate datetime
set #fromdate = DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + #year) + (#week-1), 7);
set #todate = DATEADD(wk, DATEDIFF(wk, 5, '1/1/' + #year) + (#week-1), 6) ;
;WITH dates AS
(
SELECT CONVERT(datetime,#fromDate) as Date
UNION ALL
SELECT DATEADD(d,1,[Date])
FROM dates
WHERE DATE < #toDate
)
select * from dates
SQL Server has a DATEPART function which calculates the ordinal week number of a year. However, you have to call DATEFIRST before this to define which day of the week represents the start of the week. In your case, you have stated that the start of your week is Monday (i.e. 1).
SET DATEFIRST 1;
SELECT SUM([your data column])
FROM [your table]
WHERE DATEPART(WEEKNUM, [your date column])=[your week parameter]
AND DATEPART(YEAR, [your date column])=[your year parameter]
Your description is not american standard nor isoweek. Seems like a mix of those. I never heard of that as a standard. It is nearly isoweek. So that is what this answer is based on.
Calculating iso year is a bit tricky, you can read about it here:
This is the syntax you need:
DECLARE #year int = 2010
DECLARE #week int = 2
;WITH CTE AS
(
SELECT
dateadd(wk, datediff(wk, - #week * 7,
cast(cast(#year as char(4)) as datetime) - 5), 0) startofweek
)
SELECT
replace('total for ' + convert(char(10), startofweek, 110)
+ ' to ' + convert(char(10), dateadd(day, 6, startofweek) , 110), '-', '/')
FROM CTE
Result:
total for 01/11/2010 to 01/17/2010
Isoweek 2 in 2010 is 2010-01-11
Try setting DATEFIRST (https://msdn.microsoft.com/en-ie/library/ms181598.aspx)
SET DATEFIRST 7
declare #wk int
declare #yr int
declare #EndOfWeek as datetime
set #wk = 2
set #yr = 2010
SET #EndOfWeek = dateadd (week, #wk, dateadd (year, #yr-1900, 0)) + 1 - datepart(dw, dateadd (week, #wk, dateadd (year, #yr-1900, 0)) )
SELECT
replace('total for ' + convert(char(10), dateadd(day, -6, #EndOfWeek) , 110)
+ ' to ' + convert(char(10), #EndOfWeek, 110), '-', '/')
The result:
total for 01/04/2010 to 01/10/2010
I hope it helps:
declare #year char(4) = '2014'
declare #week int = 2
select dateadd(week,#week,convert(date,#year+'-01-01',121))
Change the date format appropriate for you from this list

SQL Get "ISO Year" for ISO Week

I need to calculate the year a week is assigned to. For example the 29th december of 2003 was assigned to week one of year 2004 (this is only for europe, I think). You can take a look at this with this code:
SELECT DATEPART(isowk, '20141229');
But now I need an easy way to get the year this week is assigned to. What I currently do is not that elegant:
DECLARE #week int, #year int, #date char(8)
--set #date = '20150101'
set #date = '20141229'
SET #week = cast(datepart(isowk, #date) as int)
if #week = 1
begin
if DATEPART(MONTH, #date) = 12
begin
set #year = DATEPART(year, #date) + 1
end
else
begin
set #year = DATEPART(year, #date)
end
end
select #date "DATE", #week "WEEK", #year "YEAR"
If anybody knew a more elegant way, that would be nice :-)
This solution The code in the question does not return the correct value for the date '1-1-2027'.
The following will return the correct value with all dates i tested (and i tested quite a few).
SELECT YEAR(DATEADD(day, 26 - DATEPART(isoww, '2012-01-01'), '2012-01-01'))
As taken from: https://capens.net/content/sql-year-iso-week
This is the most compact solution I could come up with:
CASE
WHEN DATEPART(ISO_WEEK, #Date) > 50 AND MONTH(#Date) = 1 THEN YEAR(#Date) - 1
WHEN DATEPART(ISO_WEEK, #Date) = 1 AND MONTH(#Date) = 12 THEN YEAR(#Date) + 1
ELSE YEAR(#Date) END
Can be used directly inside a SELECT statement. Or you could consider creating a user-defined function that takes the #Date parameter as input and outputs the result of the case statement.
I think this solution is much more logical and easier to comprehend for ISO-8601.
"The first week of the year is the week containing the first Thursday."
see ISO Week definition
So we need to deduct the weekday of the given date from Thursday and add this to that same date to get the year.
Adding 5 and then taking the modulus of 7 to move Sunday to the previous week.
declare #TestDate date = '20270101'
select year(dateadd(day, 3 - (datepart(weekday, #TestDate) + 5) % 7, #TestDate))
This will result in 2026 which is correct.
This will give the correct result for all dates I check between 1990-2100 using this:
declare #TestDate date = '19900101'
declare #Results as table
(
TestDate date,
FirstDayofYear varchar(20),
ISOYear int,
ISOWeek int
)
while (#TestDate < '21000201')
begin
insert #Results(TestDate, FirstDayofYear, ISOYEar, ISOWeek)
select #TestDate, datename(weekday, dateadd(day, datepart(day, #TestDate) * -1 +1, #TestDate)),
year(dateadd(day, 3 - (datepart(weekday, #TestDate) + 5) % 7, #TestDate)), datepart(ISOWK, #TestDate)
set #TestDate = dateadd(day, 1, #Testdate)
if(datepart(day, #TestDate) > 7)
begin
set #TestDate = dateadd(year, 1, dateadd(day, datepart(day, #TestDate) * -1 + 1, #TestDate))
end
end
-- Show all results that are wrong:
select * from #Results
where (ISOYear <> datepart(year, TestDate) and ISOWeek < 3)
or (ISOYear = datepart(year, TestDate) and ISOWeek >= 52)
I think Bart Vanseer solution is nice and simple, but off by 1.
I believe it should be
select year(dateadd(day, 3 - ((datepart(weekday, #TestDate) + 5) % 7) , #TestDate))
Try following to find a few places were it differs
declare #TestDate date = '2000-01-01'
DECLARE #cnt INT = 0;
DECLARE #cnt_total INT = 10000;
WHILE #cnt < #cnt_total
BEGIN
SET #TestDate = dateadd(day,1, #TestDate)
if year(dateadd(day, 3 - (datepart(weekday, #TestDate) + 6) % 8, #TestDate)) <>
year(dateadd(day, 3 - ((datepart(weekday, #TestDate) + 5) % 7) , #TestDate))
BEGIN
select #TestDate, year(dateadd(day, 3 - (datepart(weekday, #TestDate) + 6) % 8, #TestDate))
select #TestDate, year(dateadd(day, 3 - ((datepart(weekday, #TestDate) + 5) % 7) , #TestDate))
END
SET #cnt = #cnt + 1;
END;
Inspired by the other answers, i came to the following solution:
declare #TestDate date = '20270101'
SELECT DATEPART(year, DATEADD(day, 4 - DATEPART(weekday, #TestDate), #TestDate))
Just get thursday of the current week to get the correct year.
Assuming DATEFIRST is set to Monday (1).
DECLARE #date DATETIME
SET #date='2014-12-29'
SELECT
CASE --Covers logic for ISO week date system which is part of the ISO 8601 date and time standard. Ref: https://en.wikipedia.org/wiki/ISO_week_date
WHEN (DATEPART(ISO_WEEK,#date) = 53) AND (DATEPART(MONTH,#date) = 1)
THEN CAST((DATEPART(YEAR, #date) - 1) AS varchar(4)) + ('-W') + CAST (RIGHT('0' + CAST(DATEPART(ISO_WEEK,#date) AS varchar(2)),2) AS varchar(2))
WHEN (DATEPART(ISO_WEEK,#date) = 1) AND (DATEPART(MONTH,#date) = 12)
THEN CAST((DATEPART(YEAR,#date) + 1) AS varchar(4)) + ('-W') + CAST (RIGHT('0' + CAST(DATEPART(ISO_WEEK,#date) AS varchar(2)),2) AS varchar(2))
ELSE CAST(DATEPART(YEAR,#date) AS varchar(4)) + ('-W') + CAST (RIGHT('0' + CAST(DATEPART(ISO_WEEK,#date) AS varchar(2)),2) AS varchar(2))
END AS ISO_week
For IsoYear, get the Thursday from IsoWeek, and then get the year.

Getting Number of weeks in a Month from a Datetime Column

I have a table called FcData and the data looks like:
Op_Date
2011-02-14 11:53:40.000
2011-02-17 16:02:19.000
2010-02-14 12:53:40.000
2010-02-17 14:02:19.000
I am looking to get the Number of weeks in That Month from Op_Date. So I am looking for output like:
Op_Date Number of Weeks
2011-02-14 11:53:40.000 5
2011-02-17 16:02:19.000 5
2010-02-14 12:53:40.000 5
2010-02-17 14:02:19.000 5
This page has some good functions to figure out the last day of any given month: http://www.sql-server-helper.com/functions/get-last-day-of-month.aspx
Just wrap the output of that function with a DATEPART(wk, last_day_of_month) call. Combining it with an equivalent call for the 1st-day-of-week will let you get the number of weeks in that month.
Use this to get the number of week for ONE specific date. Replace GetDate() by your date:
declare #dt date = cast(GetDate() as date);
declare #dtstart date = DATEADD(day, -DATEPART(day, #dt) + 1, #dt);
declare #dtend date = dateadd(DAY, -1, DATEADD(MONTH, 1, #dtstart));
WITH dates AS (
SELECT #dtstart ADate
UNION ALL
SELECT DATEADD(day, 1, t.ADate)
FROM dates t
WHERE DATEADD(day, 1, t.ADate) <= #dtend
)
SELECT top 1 DatePart(WEEKDAY, ADate) weekday, COUNT(*) weeks
FROM dates d
group by DatePart(WEEKDAY, ADate)
order by 2 desc
Explained: the CTE creates a result set with all dates for the month of the given date. Then we query the result set, grouping by week day and count the number of occurrences. The max number will give us how many weeks the month overlaps (premise: if the month has 5 Mondays, it will cover five weeks of the year).
Update
Now, if you have multiple dates, you should tweak accordingly, joining your query with the dates CTE.
Here is my take on it, might have missed something.
In Linq:
from u in TblUsers
let date = u.CreateDate.Value
let firstDay = new DateTime(date.Year, date.Month, 1)
let lastDay = firstDay.AddMonths(1)
where u.CreateDate.HasValue
select Math.Ceiling((lastDay - firstDay).TotalDays / 7)
And generated SQL:
-- Region Parameters
DECLARE #p0 Int = 1
DECLARE #p1 Int = 1
DECLARE #p2 Float = 7
-- EndRegion
SELECT CEILING(((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t3].[value], [t3].[value2]))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t3].[value], [t3].[value2]), [t3].[value]), [t3].[value2])) * 10000))) / 864000000000) / #p2) AS [value]
FROM (
SELECT [t2].[createDate], [t2].[value], DATEADD(MONTH, #p1, [t2].[value]) AS [value2]
FROM (
SELECT [t1].[createDate], CONVERT(DATETIME, CONVERT(NCHAR(2), DATEPART(Month, [t1].[value])) + ('/' + (CONVERT(NCHAR(2), #p0) + ('/' + CONVERT(NCHAR(4), DATEPART(Year, [t1].[value]))))), 101) AS [value]
FROM (
SELECT [t0].[createDate], [t0].[createDate] AS [value]
FROM [tblUser] AS [t0]
) AS [t1]
) AS [t2]
) AS [t3]
WHERE [t3].[createDate] IS NOT NULL
According to this MSDN article: http://msdn.microsoft.com/en-us/library/ms174420.aspx you can only get the current week in the year, not what that month returns.
There may be various approaches to implementing the idea suggested by #Marc B. Here's one, where no UDFs are used but the first and the last days of month are calculated directly:
WITH SampleData AS (
SELECT CAST('20110214' AS datetime) AS Op_Date
UNION ALL SELECT '20110217'
UNION ALL SELECT '20100214'
UNION ALL SELECT '20100217'
UNION ALL SELECT '20090214'
UNION ALL SELECT '20090217'
),
MonthStarts AS (
SELECT
Op_Date,
MonthStart = DATEADD(DAY, 1 - DAY(Op_Date), Op_Date)
/* alternatively: DATEADD(MONTH, DATEDIFF(MONTH, 0, Op_Date), 0) */
FROM FcData
),
Months AS (
SELECT
Op_Date,
MonthStart,
MonthEnd = DATEADD(DAY, -1, DATEADD(MONTH, 1, MonthStart))
FROM FcData
)
Weeks AS (
SELECT
Op_Date,
StartWeek = DATEPART(WEEK, MonthStart),
EndWeek = DATEPART(WEEK, MonthEnd)
FROM MonthStarts
)
SELECT
Op_Date,
NumberOfWeeks = EndWeek - StartWeek + 1
FROM Weeks
All calculations could be done in one SELECT, but I chose to split them into steps and place every step in a separate CTE so it could be seen better how the end result was obtained.
You can get number of weeks per month using the following method.
Datepart(WEEK,
DATEADD(DAY,
-1,
DATEADD(MONTH,
1,
DATEADD(DAY,
1 - DAY(GETDATE()),
GETDATE())))
-
DATEADD(DAY,
1 - DAY(GETDATE()),
GETDATE())
+1
)
Here how you can get accurate amount of weeks:
DECLARE #date DATETIME
SET #date = GETDATE()
SELECT ROUND(cast(datediff(day, dateadd(day, 1-day(#date), #date), dateadd(month, 1, dateadd(day, 1-day(#date), #date))) AS FLOAT) / 7, 2)
With this code for Sep 2014 you'll get 4.29 which is actually true since there're 4 full weeks and 2 more days.