how to convert DateDiff back to datetime? - sql-server

datediff(second,#date1, #date2)
i.e. exact difference between 2004-09-01 09:56:11.000 and 2005-02-02 08:54:02.000...output should be 5 months, x days, y hours,z minutes, m seconds.

You need that as hours and minutes? You can use dateadd to 0 date:
dateadd(second, amount, 0)
And then convert this into suitable format using convert and the formatting options like 108.
convert(varchar, dateadd(second, amount, 0), 108)

This is way more difficult than I originally thought, Calculating months and days is complicated. Here is an attempt. You should test it carefully, I imagine leapyear could also cause problems for the year calculation, so I removed it from the answer since it is not part of your question:
DECLARE #date1 datetime = '2004-09-01 09:56:11.000',
#date2 datetime = '2005-02-02 08:54:02.000'
SELECT
#date2 - #date1 difference,
datediff(month, #date1, #date2) +
CASE WHEN dateadd(month, datediff(month, #date1, #date2), #date1)>#date2
THEN -1
ELSE 0 END month,
day(#date2 - dateadd(month, datediff(month, #date1, #date2)
+ CASE WHEN dateadd(month, datediff(month, #date1, #date2), #date1)>#date2
THEN -1 ELSE 0
END, #date1)) - 1 day,
datepart(hour,#date2 - #date1) hour,
datepart(minute,#date2 - #date1) minute,
datepart(second,#date2 - #date1) second
Result now:
difference month day hour minute second
1900-06-03 22:57:51.000 5 0 22 57 51
Note: This answer will not give you exactly the same result, but it will be more accurate with seconds being rounded down.
More edit:
If you can accept not having the months as described in your comment and can accept this format x days hh:MM:ss. You can use this syntax:
SELECT
CAST((DateDiff(SECOND, #date1, #date2)) / 86400 AS varchar(7)) + ' days '
+ CAST(cast(#date2 - #date1 as time(0)) as char(8))

datediff has 3 parameters, not 2: datediff(daypart, startdate, enddate). If you need difference in seconds, use datediff(second, #date1, #date2).
To convert it back to datetime, use dateadd(datepart, number, startdate). E.g. dateadd(second, #diffResult, '1900-01-01'). For start date choose one that fits your needs.

Related

Selecting column values based on minutes [duplicate]

In SQL server 2008, I would like to get datetime column rounded to nearest hour and nearest minute preferably with existing functions in 2008.
For this column value 2007-09-22 15:07:38.850, the output will look like:
2007-09-22 15:08 -- nearest minute
2007-09-22 15 -- nearest hour
declare #dt datetime
set #dt = '09-22-2007 15:07:38.850'
select dateadd(mi, datediff(mi, 0, #dt), 0)
select dateadd(hour, datediff(hour, 0, #dt), 0)
will return
2007-09-22 15:07:00.000
2007-09-22 15:00:00.000
The above just truncates the seconds and minutes, producing the results asked for in the question. As #OMG Ponies pointed out, if you want to round up/down, then you can add half a minute or half an hour respectively, then truncate:
select dateadd(mi, datediff(mi, 0, dateadd(s, 30, #dt)), 0)
select dateadd(hour, datediff(hour, 0, dateadd(mi, 30, #dt)), 0)
and you'll get:
2007-09-22 15:08:00.000
2007-09-22 15:00:00.000
Before the date data type was added in SQL Server 2008, I would use the above method to truncate the time portion from a datetime to get only the date. The idea is to determine the number of days between the datetime in question and a fixed point in time (0, which implicitly casts to 1900-01-01 00:00:00.000):
declare #days int
set #days = datediff(day, 0, #dt)
and then add that number of days to the fixed point in time, which gives you the original date with the time set to 00:00:00.000:
select dateadd(day, #days, 0)
or more succinctly:
select dateadd(day, datediff(day, 0, #dt), 0)
Using a different datepart (e.g. hour, mi) will work accordingly.
"Rounded" down as in your example. This will return a varchar value of the date.
DECLARE #date As DateTime2
SET #date = '2007-09-22 15:07:38.850'
SELECT CONVERT(VARCHAR(16), #date, 120) --2007-09-22 15:07
SELECT CONVERT(VARCHAR(13), #date, 120) --2007-09-22 15
I realize this question is ancient and there is an accepted and an alternate answer. I also realize that my answer will only answer half of the question, but for anyone wanting to round to the nearest minute and still have a datetime compatible value using only a single function:
CAST(YourValueHere as smalldatetime);
For hours or seconds, use Jeff Ogata's answer (the accepted answer) above.
Select convert(char(8), DATEADD(MINUTE, DATEDIFF(MINUTE, 0, getdate), 0), 108) as Time
will round down seconds to 00

Find age between 15 to 25 years from a given column of date of birth? [duplicate]

I have a table listing people along with their date of birth (currently a nvarchar(25))
How can I convert that to a date, and then calculate their age in years?
My data looks as follows
ID Name DOB
1 John 1992-01-09 00:00:00
2 Sally 1959-05-20 00:00:00
I would like to see:
ID Name AGE DOB
1 John 17 1992-01-09 00:00:00
2 Sally 50 1959-05-20 00:00:00
There are issues with leap year/days and the following method, see the update below:
try this:
DECLARE #dob datetime
SET #dob='1992-01-09 00:00:00'
SELECT DATEDIFF(hour,#dob,GETDATE())/8766.0 AS AgeYearsDecimal
,CONVERT(int,ROUND(DATEDIFF(hour,#dob,GETDATE())/8766.0,0)) AS AgeYearsIntRound
,DATEDIFF(hour,#dob,GETDATE())/8766 AS AgeYearsIntTrunc
OUTPUT:
AgeYearsDecimal AgeYearsIntRound AgeYearsIntTrunc
--------------------------------------- ---------------- ----------------
17.767054 18 17
(1 row(s) affected)
UPDATE here are some more accurate methods:
BEST METHOD FOR YEARS IN INT
DECLARE #Now datetime, #Dob datetime
SELECT #Now='1990-05-05', #Dob='1980-05-05' --results in 10
--SELECT #Now='1990-05-04', #Dob='1980-05-05' --results in 9
--SELECT #Now='1989-05-06', #Dob='1980-05-05' --results in 9
--SELECT #Now='1990-05-06', #Dob='1980-05-05' --results in 10
--SELECT #Now='1990-12-06', #Dob='1980-05-05' --results in 10
--SELECT #Now='1991-05-04', #Dob='1980-05-05' --results in 10
SELECT
(CONVERT(int,CONVERT(char(8),#Now,112))-CONVERT(char(8),#Dob,112))/10000 AS AgeIntYears
you can change the above 10000 to 10000.0 and get decimals, but it will not be as accurate as the method below.
BEST METHOD FOR YEARS IN DECIMAL
DECLARE #Now datetime, #Dob datetime
SELECT #Now='1990-05-05', #Dob='1980-05-05' --results in 10.000000000000
--SELECT #Now='1990-05-04', #Dob='1980-05-05' --results in 9.997260273973
--SELECT #Now='1989-05-06', #Dob='1980-05-05' --results in 9.002739726027
--SELECT #Now='1990-05-06', #Dob='1980-05-05' --results in 10.002739726027
--SELECT #Now='1990-12-06', #Dob='1980-05-05' --results in 10.589041095890
--SELECT #Now='1991-05-04', #Dob='1980-05-05' --results in 10.997260273973
SELECT 1.0* DateDiff(yy,#Dob,#Now)
+CASE
WHEN #Now >= DATEFROMPARTS(DATEPART(yyyy,#Now),DATEPART(m,#Dob),DATEPART(d,#Dob)) THEN --birthday has happened for the #now year, so add some portion onto the year difference
( 1.0 --force automatic conversions from int to decimal
* DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,#Now),DATEPART(m,#Dob),DATEPART(d,#Dob)),#Now) --number of days difference between the #Now year birthday and the #Now day
/ DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,#Now),1,1),DATEFROMPARTS(DATEPART(yyyy,#Now)+1,1,1)) --number of days in the #Now year
)
ELSE --birthday has not been reached for the last year, so remove some portion of the year difference
-1 --remove this fractional difference onto the age
* ( -1.0 --force automatic conversions from int to decimal
* DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,#Now),DATEPART(m,#Dob),DATEPART(d,#Dob)),#Now) --number of days difference between the #Now year birthday and the #Now day
/ DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,#Now),1,1),DATEFROMPARTS(DATEPART(yyyy,#Now)+1,1,1)) --number of days in the #Now year
)
END AS AgeYearsDecimal
Gotta throw this one out there. If you convert the date using the 112 style (yyyymmdd) to a number you can use a calculation like this...
(yyyyMMdd - yyyyMMdd) / 10000 = difference in full years
declare #as_of datetime, #bday datetime;
select #as_of = '2009/10/15', #bday = '1980/4/20'
select
Convert(Char(8),#as_of,112),
Convert(Char(8),#bday,112),
0 + Convert(Char(8),#as_of,112) - Convert(Char(8),#bday,112),
(0 + Convert(Char(8),#as_of,112) - Convert(Char(8),#bday,112)) / 10000
output
20091015 19800420 290595 29
I have used this query in our production code for nearly 10 years:
SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(Date_of_birth AS INTEGER)) / 365.25) AS Age
You need to consider the way the datediff command rounds.
SELECT CASE WHEN dateadd(year, datediff (year, DOB, getdate()), DOB) > getdate()
THEN datediff(year, DOB, getdate()) - 1
ELSE datediff(year, DOB, getdate())
END as Age
FROM <table>
Which I adapted from here.
Note that it will consider 28th February as the birthday of a leapling for non-leap years e.g. a person born on 29 Feb 2020 will be considered 1 year old on 28 Feb 2021 instead of 01 Mar 2021.
So many of the above solutions are wrong DateDiff(yy,#Dob, #PassedDate) will not consider the month and day of both dates. Also taking the dart parts and comparing only works if they're properly ordered.
THE FOLLOWING CODE WORKS AND IS VERY SIMPLE:
create function [dbo].[AgeAtDate](
#DOB datetime,
#PassedDate datetime
)
returns int
with SCHEMABINDING
as
begin
declare #iMonthDayDob int
declare #iMonthDayPassedDate int
select #iMonthDayDob = CAST(datepart (mm,#DOB) * 100 + datepart (dd,#DOB) AS int)
select #iMonthDayPassedDate = CAST(datepart (mm,#PassedDate) * 100 + datepart (dd,#PassedDate) AS int)
return DateDiff(yy,#DOB, #PassedDate)
- CASE WHEN #iMonthDayDob <= #iMonthDayPassedDate
THEN 0
ELSE 1
END
End
EDIT: THIS ANSWER IS INCORRECT. I leave it in here as a warning to anyone tempted to use dayofyear, with a further edit at the end.
If, like me, you do not want to divide by fractional days or risk rounding/leap year errors, I applaud #Bacon Bits comment in a post above https://stackoverflow.com/a/1572257/489865 where he says:
If we're talking about human ages, you should calculate it the way
humans calculate age. It has nothing to do with how fast the earth
moves and everything to do with the calendar. Every time the same
month and day elapses as the date of birth, you increment age by 1.
This means the following is the most accurate because it mirrors what
humans mean when they say "age".
He then offers:
DATEDIFF(yy, #date, GETDATE()) -
CASE WHEN (MONTH(#date) > MONTH(GETDATE())) OR (MONTH(#date) = MONTH(GETDATE()) AND DAY(#date) > DAY(GETDATE()))
THEN 1 ELSE 0 END
There are several suggestions here involving comparing the month & day (and some get it wrong, failing to allow for the OR as correctly here!). But nobody has offered dayofyear, which seems so simple and much shorter. I offer:
DATEDIFF(year, #date, GETDATE()) -
CASE WHEN DATEPART(dayofyear, #date) > DATEPART(dayofyear, GETDATE()) THEN 1 ELSE 0 END
[Note: Nowhere in SQL BOL/MSDN is what DATEPART(dayofyear, ...) returns actually documented! I understand it to be a number in the range 1--366; most importantly, it does not change by locale as per DATEPART(weekday, ...) & SET DATEFIRST.]
EDIT: Why dayofyear goes wrong: As user #AeroX has commented, if the birth/start date is after February in a non leap year, the age is incremented one day early when the current/end date is a leap year, e.g. '2015-05-26', '2016-05-25' gives an age of 1 when it should still be 0. Comparing the dayofyear in different years is clearly dangerous. So using MONTH() and DAY() is necessary after all.
I believe this is similar to other ones posted here.... but this solution worked for the leap year examples 02/29/1976 to 03/01/2011 and also worked for the case for the first year.. like 07/04/2011 to 07/03/2012 which the last one posted about leap year solution did not work for that first year use case.
SELECT FLOOR(DATEDIFF(DAY, #date1 , #date2) / 365.25)
Found here.
Since there isn't one simple answer that always gives the correct age, here's what I came up with.
SELECT DATEDIFF(YY, DateOfBirth, GETDATE()) -
CASE WHEN RIGHT(CONVERT(VARCHAR(6), GETDATE(), 12), 4) >=
RIGHT(CONVERT(VARCHAR(6), DateOfBirth, 12), 4)
THEN 0 ELSE 1 END AS AGE
This gets the year difference between the birth date and the current date. Then it subtracts a year if the birthdate hasn't passed yet.
Accurate all the time - regardless of leap years or how close to the birthdate.
Best of all - no function.
I've done a lot of thinking and searching about this and I have 3 solutions that
calculate age correctly
are short (mostly)
are (mostly) very understandable.
Here are testing values:
DECLARE #NOW DATETIME = '2013-07-04 23:59:59'
DECLARE #DOB DATETIME = '1986-07-05'
Solution 1: I found this approach in one js library. It's my favourite.
DATEDIFF(YY, #DOB, #NOW) -
CASE WHEN DATEADD(YY, DATEDIFF(YY, #DOB, #NOW), #DOB) > #NOW THEN 1 ELSE 0 END
It's actually adding difference in years to DOB and if it is bigger than current date then subtracts one year. Simple right? The only thing is that difference in years is duplicated here.
But if you don't need to use it inline you can write it like this:
DECLARE #AGE INT = DATEDIFF(YY, #DOB, #NOW)
IF DATEADD(YY, #AGE, #DOB) > #NOW
SET #AGE = #AGE - 1
Solution 2: This one I originally copied from #bacon-bits. It's the easiest to understand but a bit long.
DATEDIFF(YY, #DOB, #NOW) -
CASE WHEN MONTH(#DOB) > MONTH(#NOW)
OR MONTH(#DOB) = MONTH(#NOW) AND DAY(#DOB) > DAY(#NOW)
THEN 1 ELSE 0 END
It's basically calculating age as we humans do.
Solution 3: My friend refactored it into this:
DATEDIFF(YY, #DOB, #NOW) -
CEILING(0.5 * SIGN((MONTH(#DOB) - MONTH(#NOW)) * 50 + DAY(#DOB) - DAY(#NOW)))
This one is the shortest but it's most difficult to understand. 50 is just a weight so the day difference is only important when months are the same. SIGN function is for transforming whatever value it gets to -1, 0 or 1. CEILING(0.5 * is the same as Math.max(0, value) but there is no such thing in SQL.
What about:
DECLARE #DOB datetime
SET #DOB='19851125'
SELECT Datepart(yy,convert(date,GETDATE())-#DOB)-1900
Wouldn't that avoid all those rounding, truncating and ofsetting issues?
Just check whether the below answer is feasible.
DECLARE #BirthDate DATE = '09/06/1979'
SELECT
(
YEAR(GETDATE()) - YEAR(#BirthDate) -
CASE WHEN (MONTH(GETDATE()) * 100) + DATEPART(dd, GETDATE()) >
(MONTH(#BirthDate) * 100) + DATEPART(dd, #BirthDate)
THEN 1
ELSE 0
END
)
select floor((datediff(day,0,#today) - datediff(day,0,#birthdate)) / 365.2425) as age
There are a lot of 365.25 answers here. Remember how leap years are defined:
Every four years
except every 100 years
except every 400 years
There are many answers to this question, but I think this one is close to the truth.
The datediff(year,…,…) function, as we all know, only counts the boundaries crossed by the date part, in this case the year. As a result it ignores the rest of the year.
This will only give the age in completed years if the year were to start on the birthday. It probably doesn’t, but we can fake it by adjusting the asking date back by the same amount.
In pseudopseudo code, it’s something like this:
adjusted_today = today - month(dob) + 1 - day(dob) + 1
age = year(adjusted_today - dob)
The + 1 is to allow for the fact that the month and day numbers start from 1 and not 0.
The reason we subtract the month and the day separately rather than the day of the year is because February has the annoying tendency to change its length.
The calculation in SQL is:
datediff(year,dob,dateadd(month,-month(dob)+1,dateadd(day,-day(dob)+1,today)))
where dob and today are presumed to be the date of birth and the asking date.
You can test this as follows:
WITH dates AS (
SELECT
cast('2022-03-01' as date) AS today,
cast('1943-02-25' as date) AS dob
)
select
datediff(year,dob,dateadd(month,-month(dob)+1,dateadd(day,-day(dob)+1,today))) AS age
from dates;
which gives you George Harrison’s age in completed years.
This is much cleaner than fiddling about with quarter days which will generally give you misleading values on the edges.
If you have the luxury of creating a scalar function, you can use something like this:
DROP FUNCTION IF EXISTS age;
GO
CREATE FUNCTION age(#dob date, #today date) RETURNS INT AS
BEGIN
SET #today = dateadd(month,-month(#dob)+1,#today);
SET #today = dateadd(day,-day(#dob)+1,#today);
RETURN datediff(year,#dob,#today);
END;
GO
Remember, you need to call dbo.age() because, well, Microsoft.
DECLARE #DOB datetime
set #DOB ='11/25/1985'
select floor(
( cast(convert(varchar(8),getdate(),112) as int)-
cast(convert(varchar(8),#DOB,112) as int) ) / 10000
)
source: http://beginsql.wordpress.com/2012/04/26/how-to-calculate-age-in-sql-server/
Try This
DECLARE #date datetime, #tmpdate datetime, #years int, #months int, #days int
SELECT #date = '08/16/84'
SELECT #tmpdate = #date
SELECT #years = DATEDIFF(yy, #tmpdate, GETDATE()) - CASE WHEN (MONTH(#date) > MONTH(GETDATE())) OR (MONTH(#date) = MONTH(GETDATE()) AND DAY(#date) > DAY(GETDATE())) THEN 1 ELSE 0 END
SELECT #tmpdate = DATEADD(yy, #years, #tmpdate)
SELECT #months = DATEDIFF(m, #tmpdate, GETDATE()) - CASE WHEN DAY(#date) > DAY(GETDATE()) THEN 1 ELSE 0 END
SELECT #tmpdate = DATEADD(m, #months, #tmpdate)
SELECT #days = DATEDIFF(d, #tmpdate, GETDATE())
SELECT Convert(Varchar(Max),#years)+' Years '+ Convert(Varchar(max),#months) + ' Months '+Convert(Varchar(Max), #days)+'days'
After trying MANY methods, this works 100% of the time using the modern MS SQL FORMAT function instead of convert to style 112. Either would work but this is the least code.
Can anyone find a date combination which does not work? I don't think there is one :)
--Set parameters, or choose from table.column instead:
DECLARE #DOB DATE = '2000/02/29' -- If #DOB is a leap day...
,#ToDate DATE = '2018/03/01' --...there birthday in this calculation will be
--0+ part tells SQL to calc the char(8) as numbers:
SELECT [Age] = (0+ FORMAT(#ToDate,'yyyyMMdd') - FORMAT(#DOB,'yyyyMMdd') ) /10000
CASE WHEN datepart(MM, getdate()) < datepart(MM, BIRTHDATE) THEN ((datepart(YYYY, getdate()) - datepart(YYYY, BIRTH_DATE)) -1 )
ELSE
CASE WHEN datepart(MM, getdate()) = datepart(MM, BIRTHDATE)
THEN
CASE WHEN datepart(DD, getdate()) < datepart(DD, BIRTHDATE) THEN ((datepart(YYYY, getdate()) - datepart(YYYY, BIRTHDATE)) -1 )
ELSE (datepart(YYYY, getdate()) - datepart(YYYY, BIRTHDATE))
END
ELSE (datepart(YYYY, getdate()) - datepart(YYYY, BIRTHDATE)) END
END
SELECT ID,
Name,
DATEDIFF(yy,CONVERT(DATETIME, DOB),GETDATE()) AS AGE,
DOB
FROM MyTable
How about this:
SET #Age = CAST(DATEDIFF(Year, #DOB, #Stamp) as int)
IF (CAST(DATEDIFF(DAY, DATEADD(Year, #Age, #DOB), #Stamp) as int) < 0)
SET #Age = #Age - 1
Try this solution:
declare #BirthDate datetime
declare #ToDate datetime
set #BirthDate = '1/3/1990'
set #ToDate = '1/2/2008'
select #BirthDate [Date of Birth], #ToDate [ToDate],(case when (DatePart(mm,#ToDate) < Datepart(mm,#BirthDate))
OR (DatePart(m,#ToDate) = Datepart(m,#BirthDate) AND DatePart(dd,#ToDate) < Datepart(dd,#BirthDate))
then (Datepart(yy, #ToDate) - Datepart(yy, #BirthDate) - 1)
else (Datepart(yy, #ToDate) - Datepart(yy, #BirthDate))end) Age
This will correctly handle the issues with the birthday and rounding:
DECLARE #dob datetime
SET #dob='1992-01-09 00:00:00'
SELECT DATEDIFF(YEAR, '0:0', getdate()-#dob)
Ed Harper's solution is the simplest I have found which never returns the wrong answer when the month and day of the two dates are 1 or less days apart. I made a slight modification to handle negative ages.
DECLARE #D1 AS DATETIME, #D2 AS DATETIME
SET #D2 = '2012-03-01 10:00:02'
SET #D1 = '2013-03-01 10:00:01'
SELECT
DATEDIFF(YEAR, #D1,#D2)
+
CASE
WHEN #D1<#D2 AND DATEADD(YEAR, DATEDIFF(YEAR,#D1, #D2), #D1) > #D2
THEN - 1
WHEN #D1>#D2 AND DATEADD(YEAR, DATEDIFF(YEAR,#D1, #D2), #D1) < #D2
THEN 1
ELSE 0
END AS AGE
The answer marked as correct is nearer to accuracy but, it fails in following scenario - where Year of birth is Leap year and day are after February month
declare #ReportStartDate datetime = CONVERT(datetime, '1/1/2014'),
#DateofBirth datetime = CONVERT(datetime, '2/29/1948')
FLOOR(DATEDIFF(HOUR,#DateofBirth,#ReportStartDate )/8766)
OR
FLOOR(DATEDIFF(HOUR,#DateofBirth,#ReportStartDate )/8765.82) -- Divisor is more accurate than 8766
-- Following solution is giving me more accurate results.
FLOOR(DATEDIFF(YEAR,#DateofBirth,#ReportStartDate) - (CASE WHEN DATEADD(YY,DATEDIFF(YEAR,#DateofBirth,#ReportStartDate),#DateofBirth) > #ReportStartDate THEN 1 ELSE 0 END ))
It worked in almost all scenarios, considering leap year, date as 29 feb, etc.
Please correct me if this formula have any loophole.
Declare #dob datetime
Declare #today datetime
Set #dob = '05/20/2000'
set #today = getdate()
select CASE
WHEN dateadd(year, datediff (year, #dob, #today), #dob) > #today
THEN datediff (year, #dob, #today) - 1
ELSE datediff (year, #dob, #today)
END as Age
Here is how i calculate age given a birth date and current date.
select case
when cast(getdate() as date) = cast(dateadd(year, (datediff(year, '1996-09-09', getdate())), '1996-09-09') as date)
then dateDiff(yyyy,'1996-09-09',dateadd(year, 0, getdate()))
else dateDiff(yyyy,'1996-09-09',dateadd(year, -1, getdate()))
end as MemberAge
go
CREATE function dbo.AgeAtDate(
#DOB datetime,
#CompareDate datetime
)
returns INT
as
begin
return CASE WHEN #DOB is null
THEN
null
ELSE
DateDiff(yy,#DOB, #CompareDate)
- CASE WHEN datepart(mm,#CompareDate) > datepart(mm,#DOB) OR (datepart(mm,#CompareDate) = datepart(mm,#DOB) AND datepart(dd,#CompareDate) >= datepart(dd,#DOB))
THEN 0
ELSE 1
END
END
End
GO
DECLARE #FromDate DATETIME = '1992-01-2623:59:59.000',
#ToDate DATETIME = '2016-08-10 00:00:00.000',
#Years INT, #Months INT, #Days INT, #tmpFromDate DATETIME
SET #Years = DATEDIFF(YEAR, #FromDate, #ToDate)
- (CASE WHEN DATEADD(YEAR, DATEDIFF(YEAR, #FromDate, #ToDate),
#FromDate) > #ToDate THEN 1 ELSE 0 END)
SET #tmpFromDate = DATEADD(YEAR, #Years , #FromDate)
SET #Months = DATEDIFF(MONTH, #tmpFromDate, #ToDate)
- (CASE WHEN DATEADD(MONTH,DATEDIFF(MONTH, #tmpFromDate, #ToDate),
#tmpFromDate) > #ToDate THEN 1 ELSE 0 END)
SET #tmpFromDate = DATEADD(MONTH, #Months , #tmpFromDate)
SET #Days = DATEDIFF(DAY, #tmpFromDate, #ToDate)
- (CASE WHEN DATEADD(DAY, DATEDIFF(DAY, #tmpFromDate, #ToDate),
#tmpFromDate) > #ToDate THEN 1 ELSE 0 END)
SELECT #FromDate FromDate, #ToDate ToDate,
#Years Years, #Months Months, #Days Days
What about a solution with only date functions, not math, not worries about leap year
CREATE FUNCTION dbo.getAge(#dt datetime)
RETURNS int
AS
BEGIN
RETURN
DATEDIFF(yy, #dt, getdate())
- CASE
WHEN
MONTH(#dt) > MONTH(GETDATE()) OR
(MONTH(#dt) = MONTH(GETDATE()) AND DAY(#dt) > DAY(GETDATE()))
THEN 1
ELSE 0
END
END
declare #birthday as datetime
set #birthday = '2000-01-01'
declare #today as datetime
set #today = GetDate()
select
case when ( substring(convert(varchar, #today, 112), 5,4) >= substring(convert(varchar, #birthday, 112), 5,4) ) then
(datepart(year,#today) - datepart(year,#birthday))
else
(datepart(year,#today) - datepart(year,#birthday)) - 1
end
The following script checks the difference in years between now and the given date of birth; the second part checks whether the birthday is already past in the current year; if not, it subtracts it:
SELECT year(NOW()) - year(date_of_birth) - (CONCAT(year(NOW()), '-', month(date_of_birth), '-', day(date_of_birth)) > NOW()) AS Age
FROM tableName;

Finding Months Difference in Days

I want to find the difference between two dates which should be exact in months like if the date difference is greater than 182 days them on 183rd Day it should show as 7 Months.I tried below one,
SELECT ROUND(cast(DATEDIFF(DD,'2018-01-01 18:45:30.203',GETDATE()) as float)/30,0)
but it has 15 days difference.
I wouldn’t use 30. It’s fail on some months. For example Jan 1 and March 2 since February doesn’t have at least 30 days. But I think this is what you are after. If the current day isn’t the first of the month then add a month.
SELECT
Case
when datepart(day,getdate()) > 1
Then datediff(month,'2018-01-01 18:45:30.203',GETDATE()) + 1
Else datediff(month,'2018-01-01 18:45:30.203',GETDATE())
End
I think that calculating the difference in months as an integer is very similar to calculating the age of a person. We can take the DATEDIFF in months, add this number of months to the first date and compare that to the second date to decide whether we have to subtract 1 from the difference:
DECLARE #Date1 datetime = '2018-01-01 18:45:30.203';
DECLARE #Date2 datetime = GETDATE();
SELECT
CASE
WHEN DATEADD(month, DATEDIFF(month, #Date1, #Date2), #Date1) > #Date2
THEN DATEDIFF(month, #Date1, #Date2) - 1
ELSE DATEDIFF(month, #Date1, #Date2)
END

Counting datediff from 2 date

I have 2 datetime fields, NEW_EMPLOYMENT_STARTDATE and NEW_EMPLOYMENT_ENDDATE
When I calculate the difference in months using datediff with these values for startdate and enddate:
NEW_EMPLOYMENT_STARTDATE = 2017-15-01
NEW_EMPLOYMENT_ENDDATE = 2018-14-01
With this query:
DATEDIFF(MONTH, NEW_EMPLOYMENT_STARTDATE, NEW_EMPLOYMENT_ENDDATE)
It returns 12 months, but when I have values like this:
NEW_EMPLOYMENT_STARTDATE = 2017-01-01
NEW_EMPLOYMENT_ENDDATE = 2017-31-12
It returns 11 months.
How can I get 12 months? I am using this query:
DATEDIFF(MONTH, NEW_EMPLOYMENT_STARTDATE, NEW_EMPLOYMENT_ENDDATE)-
CASE
WHEN DATEPART(DAY, NEW_EMPLOYMENT_ENDDATE) > DATEPART(DAY, NEW_EMPLOYMENT_STARTDATE)
THEN 0
ELSE 0 END AS MONTH_DIFF
It still returns 11 months.
EDIT:
According to my case, the value of the end date always less 1 day from start date, so i make a trick to check condition with case when like this:
CASE
WHEN DATEPART(DAY, NEW_EMPLOYMENT_ENDDATE) > DATEPART(DAY, NEW_EMPLOYMENT_STARTDATE)
THEN DATEDIFF(MONTH, NEW_EMPLOYMENT_STARTDATE, NEW_EMPLOYMENT_ENDDATE)+1
ELSE DATEDIFF(MONTH, NEW_EMPLOYMENT_STARTDATE, NEW_EMPLOYMENT_ENDDATE)
END AS DATEDIF
i add + 1 value to the end date so i ta can be round to next month, give feedback from my solution sir thanks
You're expectations are incorrect. When you do a DATEDIFF using MONTH, it does not consider the day portion of the dates. Consider that it is simply considering the difference in the month numbers only, regardless of the day specified.
This query:
SELECT DATEDIFF(MONTH, '20170101', '20171231') MonthsDiff
Is equivalent to this:
SELECT DATEPART(MONTH, '20171231') - DATEPART(MONTH, '20170101') MonthsDiff
The documentation for DATEDIFF states:
DATEDIFF ( datepart , startdate , enddate )
The first option is DATEPART:
datepart
Is the part of startdate and enddate that specifies the type of boundary crossed.
If you want something closer to what you expect, you can do a simple calculation based on performing the DATEDIFF in days, the dividing it by the approximate number of days in a month.
SELECT DATEDIFF(DAY, '20170101', '20171231') / ( 365 / 12 ) MonthsDiff
This will round the output to the closest month number, it all depends on how accurate you want to be. If you want months as a decimal for greater accuracy then run the below:
SELECT DATEDIFF(DAY, '20170101', '20171220') / ( 365.00 / 12 ) MonthsDiff
Note: This does not take into account leap years, for larger date ranges that might include leap years, which will make a minor difference to the accuracy.
datediff() does something very particular. It counts the number of "boundaries" between two date/time values. In your case, there are eleven boundaries -- one for each month in the year before December.
This behavior is not necessarily intuitive. If you add one day to each of your dates:
NEW_EMPLOYMENT_STARTDATE = '2017-01-02' (YYYY-MM-DD is standard format)
NEW_EMPLOYMENT_ENDDATE = '2018-01-01'
Then you will have 12 months.
If you want to round up, you can play with the dates. One method would be to normalize the first value to the beginning of the month and then add 15 days to the second value:
DATEDIFF(MONTH,
DATEADD(DAY, 1 - DAY(NEW_EMPLOYMENT_STARTDATE), NEW_EMPLOYMENT_STARTDATE)
DATEADD(DAY, 15 + 1 - DAY(NEW_EMPLOYMENT_STARTDATE), NEW_EMPLOYMENT_ENDDATE)
)
This would happen to work for the two examples you give.
Please use this select to achieve your desired result. You can use table columns instead of variables:
declare #new_employment_startdate datetime = convert (datetime, '2017-01-01', 121);
declare #new_employment_enddate datetime = convert (datetime, '2018-01-14', 121);
select
datediff(month, #new_employment_startdate, #new_employment_enddate)
+ case when
datediff(month, dateadd(ms, -3, dateadd(dd, datediff(dd, 0, #new_employment_startdate), 0)), #new_employment_startdate) = 1
and datediff(month,#new_employment_enddate , dateadd(dd, datediff(dd, 0, #new_employment_enddate) + 1, 0)) = 1
then 1
else 0
end;
Some explanations:
I check or start date is first month day AND end date is last month day. At this case I add +1 to standard datediff by month.
You can better understand my used datetime manipulations by using these example queries: https://gist.github.com/runnerlt/60636b029ab47845fdfd8924ed482e61
You need to add 1 more day in your End Date.
DATEDIFF(MONTH, NEW_EMPLOYMENT_STARTDATE, DATEADD(DD,1,NEW_EMPLOYMENT_ENDDATE))
You could match the output with MS Excel.

How to format a date with my own time part in SQL

I'm working on a SQL query which returns a integer which is the number of minutes between two given dates as follows
DATEDIFF(mi, date_one, getdate())
The above query returns difference in two dates in minutes but for getdate() I would want to supply my own time.
For example, consider
date_one= 2015-12-29 13:39:03.000
getdate() return current date and time ie., 2015-12-29 14:33:50.000
But, I want to change time part in getdate() to some 10:00:00.00 so that the getdate() is 2015-12-29 10:00:00.00 by passing an hour integer say 10.
May I know a good way to do that?
This will use getDate, but let you set your own hour. Just replace that second parameter (which is 10 with whichever hour you want). Use this expression in place of getDate() in your dateDiff function.
DATEADD(hh, 10, DATEADD(d, DATEDIFF(d, 0, getDate()), 0))
You can also add minutes, seconds, milliseconds, etc. to get what you need.
Here I am adding 633 minutes to make it 10:33 (change the first parameter to mi for minutes).
select DATEADD(mi, 633, DATEADD(d, DATEDIFF(d, 0, getDate()), 0))
See the documentation for other value for the first parameter: https://msdn.microsoft.com/en-us/library/ms186819.aspx
Here is how to use it:
DATEDIFF(mi, getDate(),
DATEADD(mi, 633, DATEADD(d, DATEDIFF(d, 0, getDate()), 0))
)
This will give you the minutes from the current time to 10:33 on the current day. Here is a sqlfiddle: http://sqlfiddle.com/#!6/9eecb7/5407
I find this function useful:
CREATE FUNCTION [dbo].[StripTimeFromDateTime]
(
#date DateTime
)
RETURNS DateTime
AS
BEGIN
RETURN DATEADD(dd, DATEDIFF(dd, 0, #date), 0)
END
This will knock the time off a datetime leaving it at 00:00:00.000. Then you can:
SELECT DATEADD(hour, 10, dbo.StripTimeFromDateTime(GetDate()))
Notice the example below:
select
cast('2015-12-28 12:15:00' as datetime),
getdate(),
cast(cast(convert(date, getdate()) as varchar(20)) + ' 10:00:00' as datetime);
|----------------------------|----------------------------|----------------------------|
| December, 28 2015 12:15:00 | December, 29 2015 20:42:35 | December, 29 2015 10:00:00 |
An example like the one you used:
with example as (
select cast('2015-12-28 12:15:00' as datetime) as date_one
)
select
date_one,
cast(cast(convert(date, getdate()) as varchar(20)) + ' 10:00:00' as datetime) as myown,
datediff(
mi,
date_one,
cast(cast(convert(date, getdate()) as varchar(20)) + ' 10:00:00' as datetime)
) as minutes
from example;
Result:
| date_one | myown | minutes |
|----------------------------|----------------------------|---------|
| December, 28 2015 12:15:00 | December, 29 2015 10:00:00 | 1305 |
Example on SQLFiddle: http://sqlfiddle.com/#!3/9eecb7/6599
The reason I used varchar is to have flexibility of typing a time such as '10:15:00' or other variations of time.
This one-liner will gives the current date with the time part replaced with the constant you want
select cast(cast(getdate() as date) as datetime) + cast(cast('10:00:00' as time) as datetime)
How this works:
Cast the getdate() result to date and then back to datetime to get the current date without the time.
select cast(cast(getdate() as date) as datetime)
Cast '10:00:00' to time and then to datetime to get 10:00:00 as datetime.
select cast(cast('10:00:00' as time) as datetime)
Add the two
select cast(cast(getdate() as date) as datetime) + cast(cast('10:00:00' as time) as datetime)
That's all
select DATEADD (hh,10, CONVERT(Datetime, CONVERT (date, GETDATE())))
First remove time and then add 10 hours.

Resources