I am trying to get the number of days,month and year from 2dates, but those are getting individual
DECLARE #datecount INT;
DECLARE #monthcount INT;
DECLARE #yearcount INT;
SELECT #datecount = (SELECT DATEDIFF(DAY, usr.registrationdate, GETDATE())
FROM users usr
WHERE usr.userid = #UserId);
SELECT #monthcount = (SELECT DATEDIFF(MONTH, usr.registrationdate, GETDATE())
FROM users usr
WHERE usr.userid = #UserId);
SELECT #yearcount = (SELECT DATEDIFF(YEAR, usr.registrationdate, GETDATE())
FROM users usr
WHERE usr.userid = #UserId);
How to cast these 3 variables? Or how can I get this in one step?
no. of days / no. of months / no. of year
What I want the output is = 3:1:2 or 3 days / 1 month / 4 years
A user-defined function can be useful for this.
Since the correct calculation for such an interval isn't as straight forward as one would assume.
The UDF below calculates the interval between 2 dates, with the output in the format of a JSON object.
CREATE FUNCTION dbo.fnGetDateInterval
(
#FromDate DATE, #ToDate DATE
)
RETURNS NVARCHAR(40)
WITH SCHEMABINDING
AS
BEGIN
DECLARE #Years INT, #Months INT, #Days INT;
DECLARE #tmpFrom DATE;
SET #Years = DATEDIFF(YEAR, #FromDate, #ToDate)
- IIF(#ToDate < DATEADD(YEAR, DATEDIFF(YEAR, #FromDate, #ToDate), #FromDate), 1, 0);
SET #tmpFrom = DATEADD(YEAR, #Years , #FromDate)
SET #Months = DATEDIFF(MONTH, #tmpFrom, #ToDate)
- IIF(#ToDate < DATEADD(MONTH,DATEDIFF(MONTH, #tmpFrom, #ToDate), #tmpFrom), 1, 0);
SET #tmpFrom = DATEADD(MONTH, #Months , #tmpFrom)
SET #Days = DATEDIFF(DAY, #tmpFrom, #ToDate)
- IIF(#ToDate < DATEADD(DAY, DATEDIFF(DAY, #tmpFrom, #ToDate), #tmpFrom), 1, 0);
RETURN CONCAT('{', '"years":', #Years,
',"months":', #Months,
',"days":', #Days, '}')
END;
DECLARE #UserId INT = 42;
SELECT CONCAT(days, ' days ', months, ' months ', years, ' years') AS DaysMonthsYears
FROM users usr
CROSS APPLY OPENJSON(dbo.fnGetDateInterval(usr.registrationdate, GETDATE()))
WITH (years INT '$.years',
months INT '$.months',
days INT '$.days') AS js
WHERE usr.userid = #UserId;
DaysMonthsYears
3 days 1 months 4 years
Test on db<>fiddle here
Input
startdate - 2020-05-01 10:05:07.000
enddate - 2020-05-18 12:08:07.000
Expected Output
12D:02H:03M
I need output like aobve which is having hours minutes with days
Iam having query from which iam getting only working days ,below is the query
SELECT (DATEDIFF(dd, receive_date, GETDATE()) + 1)
-(DATEDIFF(wk, receive_date, GETDATE()) * 2)
-(CASE WHEN DATENAME(dw, receive_date) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, GETDATE()) = 'Saturday' THEN 1 ELSE 0 END) from email
other query i have like this
select dbo.fn_WorkDays(receive_date, getdate() ) from email
You could break it down to total seconds and then pull out the parts you need.
EDIT
Ok, I see now that you need to use only weekdays. I am certain there is a more eloquent way to do this, but this should give you a start. I would imagine using a calendar table might make it easier.
I made it so that if one of the start or end dates started on a weekend the calculation should still be correct.
Consider the following:
DECLARE #startdate as datetime = '2020-05-01 10:05:07.000'
DECLARE #enddate as datetime = '2020-05-18 12:08:07.000'
;WITH CTE AS
(
SELECT #startDate stDate, DATEADD(second, -1, DATEADD(day, DATEDIFF(day, 0, #startdate)+1, 0)) EndDate
UNION ALL
SELECT
CASE WHEN DATEADD(day,1,stDate) < DATEADD(dd, 0, DATEDIFF(dd, 0, #enddate))
THEN DATEADD(dd, 0, DATEDIFF(dd, 0, DATEADD(day,1,stDate) ))
ELSE #enddate
END,
CASE WHEN DATEADD(day,1,stDate) < DATEADD(dd, 0, DATEDIFF(dd, 0, #enddate))
THEN DATEADD(second, -1, DATEADD(day, DATEDIFF(day, 0, DATEADD(day,1,stDate))+1, 0))
ELSE #enddate
END EndDate
FROM CTE
WHERE DATEADD(day,1,stDate) <= #enddate
)
,
ctSeconds as
(
SELECT COUNT(*) DayCount,MIN(stDate) stDate, MAX(EndDate) EndDate
from CTE
WHERE DATENAME(dw,stDate) NOT IN ('SATURDAY', 'SUNDAY')
)
SELECT
FORMAT(DayCount, '00') + 'D:'
+ FORMAT ( (TotalSeconds % 86400) / 3600,'00') + 'H:'
+ FORMAT ( (TotalSeconds % 3600) / 60, '00') + 'M' AS SPAN
FROM
(
SELECT DATEDIFF(SECOND,stDate, EndDate) TotalSeconds, DayCount from ctSeconds
) x
RESULT
SPAN
12D:02H:03M
Check below query, It will help you
declare #startDate as datetime = '2020-05-02 15:05:06.000'
,#endDate as datetime = '2020-05-18 12:08:07.000'
-- Minutes calculation START
declare #startRemainingMin int=datediff(SECOND,cast('1900-01-01' as time),cast(#startDate as time))
,#endRemainingMin int=datediff(SECOND,cast('1900-01-01' as time),cast(#endDate as time))
,#diffMin int
set #diffMin = #endRemainingMin-#startRemainingmin
-- Uncount if #endDate is sunday or saturday
if(datename(DW,#endDate)='Sunday' or datename(DW,#endDate)='Saturday')
begin
select #diffMin=-1*#startRemainingmin
end
-- Uncount if #startDate is sunday or saturday
if(datename(DW,#startDate)='Sunday' or datename(DW,#startDate)='Saturday')
begin
select #diffMin=#endRemainingMin
end
--Minutes calculation END
if(#diffMin<0)
begin
select #diffMin=86400+#diffMin
end
;with cteAllDate as(
select #startDate as dt
union all
select
dt+1
from cteAllDate where dateadd(day,1,dt)<=#endDate
)
select cast(count(1)-sum(iif((datename(DW,dt)='Sunday' or datename(DW,dt)='Saturday'),1,0 )) as varchar(5)) + 'D:'
+ format ((#diffMin/3600),'00') + 'H:'
+ format ( (#diffMin%3600/60), '00') + 'M:'
+ format ( (#diffMin%60), '00') + 'S' as result
from cteAllDate
Output:
result
10D:12H:08M:07S
I want to find the exact month difference. for e.g. 6 Months difference from today,
Consider Today and 6 Months before is 2018-01-14. If you see the dates 6 Months is over and it is 6 Months ,1 day.I want to display it as 7 months . i tried the below query but it returns complete months.
select DATEDIFF(MONTH,'2018-01-15 10:49:36.237',GETDATE())
Two ways:
One using select:
select
datediff(month,'2012-April-09','2013-April-08') MonthsInService
,datediff(day,'2012-April-09','2013-April-08')/365 YearsInService
Second using a function:
CREATE FUNCTION [dbo].[getFullYears]
(
#dateX datetime,
#dateY datetime
)
RETURNS int
AS
BEGIN
DECLARE #y int
SET #y =DATEDIFF(year,#dateX,#dateY)
IF (#dateY < DATEADD(year, #y, #dateX)) SET #y = #y -1
RETURN #y
END
select dbo.getFullYears('2012-April-09','2013-April-09') --1
select dbo.getFullYears('2012-April-09','2013-April-08') --0
refer this post as well for month calculation, it will complete my answer overall.
You can find year, month and day by this
WITH ex_table AS (
SELECT '2018-01-15 10:49:36.237' 'monthbefore',
getdate() 'visitdatetime')
SELECT CAST(DATEDIFF(yy, t.monthbefore, t.visitdatetime) AS varchar(4)) +' year '+
CAST(DATEDIFF(mm, DATEADD(yy, DATEDIFF(yy, t.monthbefore, t.visitdatetime), t.monthbefore), t.visitdatetime) AS varchar(2)) +' month '+
CAST(DATEDIFF(dd, DATEADD(mm, DATEDIFF(mm, DATEADD(yy, DATEDIFF(yy, t.monthbefore, t.visitdatetime), t.monthbefore), t.visitdatetime), DATEADD(yy, DATEDIFF(yy, t.monthbefore, t.visitdatetime), t.monthbefore)), t.visitdatetime) AS varchar(2)) +' day' AS result
FROM ex_table t
You can use this :
declare #date as varchar(50)
set #date = '2018-01-15 10:49:36.237'
select DATEDIFF(MONTH, #date, GETDATE()) as [Month], DATEDIFF(day, #date, GETDATE())%30 as [Day]
Output
Month Day
6 2
In Microsoft SQL Server, I have a week number
(from DATEPART(wk, datecol))
But what I would like to do is turn this back into the date span for that week.
For example,
SELECT DATEPART(wk, GETDATE())
yields 10. I would like to derive 3/1/2009 and 3/7/2009 from this number.
Is this possible?
Quassnoi's answer works, but kind of leaves you on the hook for cleaning up the dates if they are dates in the middle of the day (his start of week leaves you one day earlier than you need to be if you use a time in the middle of the day -- you can test using GETDATE()).
I've used something like this in the past:
SELECT
CONVERT(varchar(50), (DATEADD(dd, ##DATEFIRST - DATEPART(dw, DATECOL), DATECOL)), 101),
CONVERT(varchar(50), (DATEADD(dd, ##DATEFIRST - DATEPART(dw, DATECOL) - 6, DATECOL)), 101)
A side benefit of this is that by using ##DATEFIRST you can handle nonstandard week starting days (the default is Sunday, but with SET ##DATEFIRST you can change this).
It seems crazy that simple date manipulation in SQL Server has to be this arcane, but there you go...
You can set #WeekNum and #YearNum to whatever you want - in this example they are derived from the #datecol variable, which is set to GETDATE() for purposes of illustration. Once you have those values- you can calculate the date range for a week by using the following:
DECLARE #datecol datetime = GETDATE();
DECLARE #WeekNum INT
, #YearNum char(4);
SELECT #WeekNum = DATEPART(WK, #datecol)
, #YearNum = CAST(DATEPART(YY, #datecol) AS CHAR(4));
-- once you have the #WeekNum and #YearNum set, the following calculates the date range.
SELECT DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + #YearNum) + (#WeekNum-1), 6) AS StartOfWeek;
SELECT DATEADD(wk, DATEDIFF(wk, 5, '1/1/' + #YearNum) + (#WeekNum-1), 5) AS EndOfWeek;
To answer your question:
--CHANGE A WEEK NUMBER BACK INTO A DATE FOR THE FIRST DATE OF THE WEEK
DECLARE #TaskWeek INT = 17
DECLARE #TaskYear INT = 2013
SELECT DATEADD(WEEK, #TaskWeek - 1,DATEADD(dd, 1 - DATEPART(dw, '1/1/' + CONVERT(VARCHAR(4),#TaskYear)), '1/1/' + CONVERT(VARCHAR(4),#TaskYear)))
If your week starts from Monday (on SQL Server 2008)
select datecol,
DATEPART(ISOWK, datecol) as week,
((DATEPART(dw, datecol)+5)%7)+1 as weekday,
(DATEADD(dd, -((DATEPART(dw, datecol)+5)%7), datecol)) as Monday,
(DATEADD(dd, -((DATEPART(dw, datecol)+5)%7)+6, datecol)) as Sunday
SELECT DATECOL - DATEPART(weekday, DATECOL), DATECOL - DATEPART(weekday, DATECOL) + 7
How about a function that jumps to the week before that week number and then steps through the next few days until the week number changes (max 7 steps), returning the new date?
CREATE FUNCTION dbo.fnGetDateFromWeekNo
(#weekNo int , #yearNo int)
RETURNS smalldatetime
AS
BEGIN
DECLARE #tmpDate smalldatetime
set #tmpdate= cast(cast (#yearNo as varchar) + '-01-01' as smalldatetime)
-- jump forward x-1 weeks to save counting through the whole year
set #tmpdate=dateadd(wk,#weekno-1,#tmpdate)
-- make sure weekno is not out of range
if #WeekNo <= datepart(wk,cast(cast (#yearNo as varchar) + '-12-31' as smalldatetime))
BEGIN
WHILE (datepart(wk,#tmpdate)<#WeekNo)
BEGIN
set #tmpdate=dateadd(dd,1,#tmpdate)
END
END
ELSE
BEGIN
-- invalid weeknumber given
set #tmpdate=null
END
RETURN #tmpDate
END
I've taken elindeblom's solution and modified it - the use of strings (even if cast to dates) makes me nervous for the different formats of dates used around the world. This avoids that issue.
While not requested, I've also included time so the week ends 1 second before midnight:
DECLARE #WeekNum INT = 12,
#YearNum INT = 2014 ;
SELECT DATEADD(wk,
DATEDIFF(wk, 6,
CAST(RTRIM(#YearNum * 10000 + 1 * 100 + 1) AS DATETIME))
+ ( #WeekNum - 1 ), 6) AS [start_of_week],
DATEADD(second, -1,
DATEADD(day,
DATEDIFF(day, 0,
DATEADD(wk,
DATEDIFF(wk, 5,
CAST(RTRIM(#YearNum * 10000
+ 1 * 100 + 1) AS DATETIME))
+ ( #WeekNum + -1 ), 5)) + 1, 0)) AS [end_of_week] ;
Yes, I know I'm still casting but from a number. It "feels" safer to me.
This results in:
start_of_week end_of_week
----------------------- -----------------------
2014-03-16 00:00:00.000 2014-03-22 23:59:59.000
Another way to do it:
declare #week_number int;
declare #start_weekday int = 0 -- Monday
declare #end_weekday int = 6 -- next Sunday
select #week_number = datediff(week, 0, getdate())
select
dateadd(week, #week_number, #start_weekday) as WEEK_FIRST_DAY,
dateadd(week, #week_number, #end_weekday) as WEEK_LAST_DAY
Explanation:
#week_number is computed based on the initial calendar date '1900-01-01'. Replace getdate() by whatever date you want.
#start_weekday is 0 if Monday. If Sunday, then declare it as -1
#end_weekday is 6 if next Sunday. If Saturday, then declare it as 5
Then dateadd function, will add the given number of weeks and the given number of days to the initial calendar date '1900-01-01'.
dateadd(
dd,
datepart(wk, #Date)*7,
convert(smalldatetime, convert(char,year(max(#Date)))+convert(char, '-01-01'))
)-1
Here you just have to pass year and week number.
DECLARE #Year VARCHAR(4)
SET #Year= '2012'
DECLARE #FirstDate DATETIME
SET #FirstDate = (SELECT DATEADD(dd,1,(SELECT DATEADD(wk,DATEPART(wk,GETDATE())-1,Convert(DAteTime,'01-01-' + #Year))))
)
DECLARE #LastDate DATETIME
SET #LastDate =(SELECT DATEADD(dd,4,#FirstDate))
SELECT #FirstDate
,#LastDate
This should work regardless of ##DATEFIRST
ALTER FUNCTION dbo.DEV_VW_WeekSerial
(#YearNum int,
#WeekNum int,
#DayNum int)
RETURNS Date AS
BEGIN
DECLARE #FirstDayYear As Date;
SET #FirstDayYear='01/01/' + CAST(#YearNum As varchar)
RETURN dateadd(d,(#DayNum-datepart(weekday,#FirstDayYear)),dateadd(week, #WeekNum-1,#FirstDayYear))
END
Give it #Year and #Week,
return first date of that week.
Declare #Year int
,#Week int
,#YearText varchar(4)
set #Year = 2009
set #Week = 10
set #YearText = #Year
print dateadd(day
,1 - datepart(dw, #YearText + '-01-01')
+ (#Week-1) * 7
,#YearText + '-01-01')
I just incorporated the SELECT with a CASE statement (For my situation Monday marked the first day of the week, and didn't want to deal with the SET DATEFIRST command:
CASE DATEPART(dw,<YourDateTimeField>)
WHEN 1 THEN CONVERT(char(10), DATEADD(DD, -6, <YourDateTimeField>),126) + ' to ' + CONVERT(char(10), <YourDateTimeField>,126)
WHEN 2 THEN CONVERT(char(10), <YourDateTimeField>,126) + ' to ' + CONVERT(char(10), DATEADD(DD, 6, <YourDateTimeField>),126)
WHEN 3 THEN CONVERT(char(10), DATEADD(DD, -1, <YourDateTimeField>),126) + ' to ' + CONVERT(char(10), DATEADD(DD, 5, <YourDateTimeField>),126)
WHEN 4 THEN CONVERT(char(10), DATEADD(DD, -2, <YourDateTimeField>),126) + ' to ' + CONVERT(char(10), DATEADD(DD, 4, <YourDateTimeField>),126)
WHEN 5 THEN CONVERT(char(10), DATEADD(DD, -3, <YourDateTimeField>),126) + ' to ' + CONVERT(char(10), DATEADD(DD, 3, <YourDateTimeField>),126)
WHEN 6 THEN CONVERT(char(10), DATEADD(DD, -4, <YourDateTimeField>),126) + ' to ' + CONVERT(char(10), DATEADD(DD, 2, <YourDateTimeField>),126)
WHEN 7 THEN CONVERT(char(10), DATEADD(DD, -5, <YourDateTimeField>),126) + ' to ' + CONVERT(char(10), DATEADD(DD, 1, <YourDateTimeField>),126)
ELSE 'UNK'
END AS Week_Range
The most votes answer works fine except the 1st week and last week of year. When datecol value is '2009-01-01', the result will be 01/03/2009 and 12/28/2008.
My solution:
DECLARE #Date date = '2009-03-01', #WeekNum int, #StartDate date;
SELECT #WeekNum = DATEPART(WEEK, #Date);
SELECT #StartDate = DATEADD(DAY, -(DATEPART(WEEKDAY, DATEADD(YEAR, DATEDIFF(YEAR, 0, #Date), 0)) + 6), DATEADD(YEAR, DATEDIFF(YEAR, 0, #Date), 0));
SELECT CONVERT(nvarchar, CASE WHEN #WeekNum = 1 THEN CAST(DATEADD(YEAR, DATEDIFF(YEAR, 0, #Date), 0) AS date) ELSE DATEADD(DAY, 7 * #WeekNum, #StartDate) END, 101) AS StartOfWeek
,CONVERT(nvarchar, CASE WHEN #WeekNum = DATEPART(WEEK, DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, #Date) + 1, 0))) THEN DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, #Date) + 1, 0)) ELSE DATEADD(DAY, 7 * #WeekNum + 6, #StartDate) END, 101) AS EndOfWeek;
This will display 01/01/2009 and 01/03/2009 for the 1st week, and display 03/01/2009 and 03/07/2009 for the 10th week.
I think this would be what you want exactly. You can replace the variables with their expressions as you wish.
declare #IntWeek as varchar(20)
SET #IntWeek = '201820'
SELECT
DATEADD(wk, DATEDIFF(wk, ##DATEFIRST, LEFT(#IntWeek,4) + '-01-01') +
(cast(RIGHT(#IntWeek, 2) as int) -1), ##DATEFIRST) AS StartOfWeek
SELECT DATEADD(week, #weekNumber - 1, DATEADD(DAY, ##datefirst - DATEPART(weekday, CAST(YEAR(GETDATE()) AS VARCHAR) + '-01-01') - 6, CAST(YEAR(GETDATE()) AS VARCHAR) + '-01-01'))
DECLARE #dayval int,
#monthval int,
#yearval int
SET #dayval = 1
SET #monthval = 1
SET #yearval = 2011
DECLARE #dtDateSerial datetime
SET #dtDateSerial = DATEADD(day, #dayval-1,
DATEADD(month, #monthval-1,
DATEADD(year, #yearval-1900, 0)
)
)
DECLARE #weekno int
SET #weekno = 53
DECLARE #weekstart datetime
SET #weekstart = dateadd(day, 7 * (#weekno -1) - datepart (dw, #dtDateSerial), #dtDateSerial)
DECLARE #weekend datetime
SET #weekend = dateadd(day, 6, #weekstart)
SELECT #weekstart, #weekend
Answer:
select DateAdd(day,-DATEPart(DW,<Date>), <Date>) [FirstDayOfWeek] ,DateAdd(day,-DATEPart(DW,<Date>)+6, <Date>) [LastDayOfWeek]
FROM <TABLE>
This works for me:
select
convert(varchar(50), dateadd(dd, - datepart(dw, DATECOL) + 1, DATECOL), 101),
convert(varchar(50), dateadd(dd, - datepart(dw, DATECOL) + 7, DATECOL), 101)
I didn't take the time to test out every answer on here, but nothing seems as simple and as efficient as this:
DECLARE #WeekNum int
DECLARE #YearNum char(4)
SELECT DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + #YearNum) + (#WeekNum-1), 6) AS StartOfWeek
SELECT DATEADD(wk, DATEDIFF(wk, 5, '1/1/' + #YearNum) + (#WeekNum-1), 5) AS EndOfWeek