Get the remaining days between two dates - sql

I am trying to calculate the remaining year, month and days between 2 dates using the method below, but I cannot get the remaining dates right. Is there a function or different method I should try?
Select (DATEDIFF(m, '1965-10-17', '2021-04-07')) /12 as AgeYr ,
(DATEDIFF(m, '1965-10-17', '2021-04-07')) %12 as AgeMth,
(DATEDIFF(d, '1965-10-17', '2021-04-07')) %30 as AgeDay;
This is the result of my code
AgeYr
AgeMth
AgeDay
55
6
10
but the result should be
AgeYr
AgeMth
AgeDay
55
6
21

DECLARE #date datetime, #startdate datetime, #enddate datetime, #years int, #months int, #days int
SELECT #startdate = '1965-10-17'
SELECT #enddate = '2021-04-07'
SELECT #date = #startdate
SELECT #years = DATEDIFF(yy, #startdate, #enddate) - CASE WHEN (MONTH(#date) > MONTH(#enddate)) OR (MONTH(#date) = MONTH(#enddate) AND DAY(#date) > DAY(#enddate)) THEN 1 ELSE 0 END
SELECT #startdate = DATEADD(yy, #years, #startdate)
SELECT #months = DATEDIFF(m, #startdate, #enddate) - CASE WHEN DAY(#date) > DAY(#enddate) THEN 1 ELSE 0 END
SELECT #startdate = DATEADD(m, #months, #startdate)
SELECT #days = DATEDIFF(d, #startdate, #enddate)
SELECT #years years, #months months, #days days
Output:
AgeYr
AgeMth
AgeDay
55
5
21
db<>fiddle here
You can also do it with common table expression:
;with years as
(SELECT (DATEDIFF(yy, '1965-10-17', '2021-04-07') - CASE WHEN (MONTH('1965-10-17') > MONTH('2021-04-07')) OR (MONTH('1965-10-17') = MONTH('2021-04-07') AND DAY('1965-10-17') > DAY('2021-04-07')) THEN 1 ELSE 0 END)AgeYr,
'1965-10-17' startdate)
,months as
(SELECT (DATEDIFF(m, DATEADD(yy, years.AgeYr, '1965-10-17'), '2021-04-07') - CASE WHEN DAY('1965-10-17') > DAY('2021-04-07') THEN 1 ELSE 0 END)AgeMth, DATEADD(yy, years.AgeYr, '1965-10-17') temp
from years)
,days as
(select DATEDIFF(d, DATEADD(m, months.AgeMth, temp), '2021-04-07')AgeDay from months)
select years.AgeYr,months.AgeMth,days.AgeDay from years,months,days
Output:
AgeYr
AgeMth
AgeDay
55
5
21
db<>fiddle here

Related

Difference in Days Between Two Dates with Years, Months, and Days

I'm not a SQL expert, would you know if it's possible to have a query provide Days Between Two Dates to count days outstanding with today's date and output: Years, Months, Days and outstanding days providing 30 Days, 60 Days, 90 Days?
If I Declare "Years, Months, Days" from "Check_Date" and "Created_Date".
SQL provides a separate window, and, I only see Declared "FromDate" time
with "ToDate" displaying total Years, Months, Days. I am looking for a way
to have results provide a roll BY "Created_Date" records and include:
Years, Months, Days and outstanding days providing 30 Days, 60 Days, 90 Days? Can you suggest something with a similar result?
Scrip Code:
DECLARE #FromDate DATETIME = '2015-01-01 00:00:00',
#ToDate DATETIME = '2019-09-18 00:00:00',
#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
SELECT DISTINCT
ge.Name, --table columns
ge.Entity_Type,
ge.Entity_Number,
bc.Super_Entity_ID,
ch.Check_Date, --check created
ch.Created_Date, --if payment was received
ch.Check_Number,
ch.Amount,
vn.Vendor_Name
Check_Date,Created_Date,DATEDIFF("DAY",Check_Date,Created_Date) AS DAY
FROM dbo.gl_entities AS ge
INNER JOIN
dbo.super_entity AS se
ON ge.Super_Entity_ID = se.Super_Entity_ID
INNER JOIN
dbo.bank_codes AS bc
ON se.Super_Entity_ID = bc.Super_Entity_ID
INNER JOIN
dbo.checks AS ch
ON bc.Bank_Code_ID = ch.Bank_Code_ID
INNER JOIN
dbo.vendors AS vn
ON ch.Vendor_ID = vn.Vendor_ID
WHERE
ge.Active = 1 and vn.active = 1 and (ge.IS_Shadow = 1 OR se.IS_Tiered = 0)
AND CHECK_DATE > '20150101 00:00:00'
AND CHECK_DATE< '20190918 00:00:00'
ORDER BY ch.Check_Date, ch.Created_Date
To simply repeat them in their own columns in the query:
DECLARE #FromDate DATETIME = '2015-01-01 00:00:00',
#ToDate DATETIME = '2019-09-18 00:00:00',
#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 DISTINCT
ge.Name, --table columns
ge.Entity_Type,
ge.Entity_Number,
bc.Super_Entity_ID,
ch.Check_Date, --check created
ch.Created_Date, --if payment was received
ch.Check_Number,
ch.Amount,
vn.Vendor_Name,
Check_Date,Created_Date,DATEDIFF("DAY",Check_Date,Created_Date) AS DAY,
#FromDate FromDate, #ToDate ToDate, #Years Years, #Months Months, #Days Days
FROM
. . .
If you run into problems with the DISTINCT clause, you can always use a subquery. If you want Years, Months, Days to be different based on one of the columns, you'll have to elaborate and then we can move everything you did in the SET statements into the SELECT statement.
Without your tables and data I cannot test very well.
pseudocode to try and demonstrate moving set statements to select statements
declare #begin date = '2018-01-01'
declare #end date = '2019-01-01'
declare #middletest int = datediff("dd", #begin, #end)/2
declare #middledate date = dateadd("dd", #middletest, #begin)
declare #middlemonth int = month(#middledate)
select #middlemonth half_month, #middledate middle_date
-- ,other_columns here
from table
where something
Start replacing.
#middlemonth is in the select statement so replace it with month(#middledate).
declare #begin date = '2018-01-01'
declare #end date = '2019-01-01'
declare #middletest int = datediff("dd", #begin, #end)/2
declare #middledate date = dateadd("dd", #middletest, #begin)
select month(#middledate) half_month, #middledate middle_date
-- ,other_columns here
from table
where something
#middledate is now in the select statement in 2 places so replace it with dateadd("dd", #middletest, #begin) each time.
declare #begin date = '2018-01-01'
declare #end date = '2019-01-01'
declare #middletest int = datediff("dd", #begin, #end)/2
select month(dateadd("dd", #middletest, #begin)) half_month,
dateadd("dd", #middletest, #begin) middle_date
-- ,other_columns here
from table
where something
Continue along.
declare #begin date = '2018-01-01'
declare #end date = '2019-01-01'
select month(dateadd("dd", datediff("dd", #begin, #end)/2, #begin)) half_month,
dateadd("dd", datediff("dd", #begin, #end)/2, #begin) middle_date
-- ,other_columns here
from table
where something
And you can, as desired, replace things with values from the table. If the table has a column start_date and you want that to be the begin and then use the current date as the end:
select month(dateadd("dd", datediff("dd", start_date, getdate())/2, start_date)) half_month,
dateadd("dd", datediff("dd", start_date, getdate())/2, start_date) middle_date
-- ,other_columns here
from table
where something

Get date difference in year, month, and days SQL

Is there a way to calculate how old someone is based on today's date and their birthday then display it in following manners:
If a user is less than (<) 1 year old THEN show their age in MM & days.
Example: 10 months & 2 days old
If a user is more than 1 year old AND less than 6 years old THEN show their age in YY & MM & days.
Example: 5 years & 3 months & 10 days old
If a user is more than 6 years old THEN display their age in YY.
Example: 12 years
This is basically what you are looking for:
DECLARE #date1 DATETIME
, #date2 DATETIME;
SELECT #date1 = '1/1/2008'
, #date2 = GETDATE();
SELECT CASE
WHEN DATEDIFF(YEAR, #date1, #date2) < 1 THEN CAST(DATEDIFF(mm, #date1, #date2) AS VARCHAR)+' Months & '+CAST(DATEDIFF(dd, DATEADD(mm, DATEDIFF(mm, #date1, #date2), #date1), #date2) AS VARCHAR)+' Days'
WHEN DATEDIFF(YEAR, #date1, #date2) BETWEEN 1 AND 5 THEN CAST(DATEDIFF(mm, #date1, #date2) / 12 AS VARCHAR)+' Years & '+CAST(DATEDIFF(mm, #date1, #date2) % 12 AS VARCHAR)+' Months'
WHEN DATEDIFF(YEAR, #date1, #date2) >= 6 THEN CAST(DATEDIFF(YEAR, #date1, #date2) AS VARCHAR)+' Years'
END;
Result for when a user is less than (<) 1 year old THEN show their age in MM & days:
Result for when a user is more than 1 year old AND less than 6 years old THEN show their age in YY & MM & days:
Result for when a user is more than 6 years old THEN display their age in YY:
from this previous question
How to calculate age in T-SQL with years, months, and days
you can do procedure like this
CREATE procedure [dbo].[proc_datediff]
(
#date datetime
)
as
begin
DECLARE #diff varchar(70)
DECLARE #tmpdate datetime, #years int, #months int, #days int
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 #diff=
case
when #years < 1 then
concat( #months,' Months ',#days,' days ' )
when #years >=1 and #years < 6
then
concat(#years,' year ', #months,' Months ',#days,' days ' )
when #years >= 6 then
concat( #years,' years ' )
end;
select #diff
end
execute proc_datediff '1/1/2016'
go
CREATE FUNCTION [dbo].[FindDateDiff](#Date1 date,#Date2 date, #IncludeTheEnDate bit)
RETURNS TABLE
AS
RETURN
(
SELECT
CALC.Years,CALC.Months,D.Days,
Duration = RTRIM(Case When CALC.Years > 0 Then CONCAT(CALC.Years, ' year(s) ') Else '' End
+ Case When CALC.Months > 0 Then CONCAT(CALC.Months, ' month(s) ') Else '' End
+ Case When D.Days > 0 OR (CALC.Years=0 AND CALC.Months=0) Then CONCAT(D.Days, ' day(s)') Else '' End)
FROM (VALUES(IIF(#Date1<#Date2,#Date1,#Date2),DATEADD(DAY, IIF(#IncludeTheEnDate=0,0,1), IIF(#Date1<#Date2,#Date2,#Date1)))) T(StartDate, EndDate)
CROSS APPLY(Select
TempEndYear = Case When ISDATE(CONCAT(YEAR(T.EndDate), FORMAT(T.StartDate,'-MM-dd')))=1 Then CONCAT(YEAR(T.EndDate), FORMAT(T.StartDate,'-MM-dd'))
Else CONCAT(YEAR(T.EndDate),'-02-28') End
) TEY
CROSS APPLY(Select EndYear = Case When TEY.TempEndYear > T.EndDate Then DATEADD(YEAR, -1, TEY.TempEndYear) Else TEY.TempEndYear End) EY
CROSS APPLY(Select
Years = DATEDIFF(YEAR,T.StartDate,EY.EndYear),
Months = DATEDIFF(MONTH,EY.EndYear,T.EndDate)-IIF(DAY(EY.EndYear)>DAY(T.EndDate),1,0)
) CALC
CROSS APPLY(Select Days = DATEDIFF(DAY,DATEADD(MONTH,CALC.Months,DATEADD(YEAR,CALC.Years,T.StartDate)),T.EndDate)) D
)
Sample:
Select [From] = '2021-01-01',[To] = '2021-12-31',IncludeEndDate='Yes',* From dbo.FindDateDiff('2021-01-01','2021-12-31',1)
Select [From] = '2021-01-01',[To] = '2021-12-31',IncludeEndDate='No',* From dbo.FindDateDiff('2021-01-01','2021-12-31',0)
Select [From] = '2015-12-15',[To] = '2018-12-14',IncludeEndDate='Yes',* From dbo.FindDateDiff('2015-12-15','2018-12-14',1)
Select [From] = '2015-12-15',[To] = '2018-12-14',IncludeEndDate='No',* From dbo.FindDateDiff('2015-12-15','2018-12-14',0)
Probably not the most efficient way to go about it, but here's how I did it:
I had to first get the date difference between today's date and person's birthdate. I used it to get years, months, days, etc by combining it with ABS(), and Remainder (%) function.
declare #year int = 365
declare #month int = 30
declare #sixYears int = 2190
select
--CAST(DATEDIFF(mm, a.BirthDateTime, getdate()) AS VARCHAR) as GetMonth,
--CAST(DATEDIFF(dd, DATEADD(mm, DATEDIFF(mm, a.BirthDateTime, getdate()), a.BirthDateTime), getdate()) AS VARCHAR) as GetDays,
CASE
WHEN
DATEDIFF(dd,a.BirthDateTime,getdate()) < #year
THEN
cast((DATEDIFF(dd,a.BirthDateTime,getdate()) / (#month)) as varchar) +' Months & ' +
CAST(ABS(DATEDIFF(dd, DATEADD(mm, DATEDIFF(mm, a.BirthDateTime, getdate()), a.BirthDateTime), getdate())) AS VARCHAR)
+ ' Days'
WHEN
DATEDIFF(dd,a.BirthDateTime,getdate()) between #year and #sixYears
THEN
cast((DATEDIFF(dd,a.BirthDateTime,getdate()) / (#year)) as varchar) +' Years & ' +
CAST((DATEDIFF(mm, a.BirthDateTime, getdate()) % (12)) AS VARCHAR) + ' Months'
WHEN DATEDIFF(dd,a.BirthDateTime,getdate()) > #sixYears
THEN cast(a.Age as varchar) + ' Years'
end as FinalAGE,
dc.DayMarker = cast(getdate() as date)
DAYmarker is your date field.

SQL Table-Valued User-Defined Functions between TWo dates

I need to build a table valued user defined function using two parameters
input like select * from func_1('01/01/2012','09/09/2015');
output should be like :
month quator semi_annual annual
1 1 1 2012
2 1 1 2012
3 1 1 2012
4 2 1 2012
5 2 1 2012
6 2 1 2012
7 3 2 2012
. . . ...
. . . ....
upto
9 3 2 2015
I need a table valued function for this.
i tried a code like this
create function func3_D_D
(#startDate date, #endDate date)
RETURNS #dates table
(months int,quatorly int,Semi_anuual int,Annual int)
As
Begin
declare
#months int,
#quatorly int,
#Semi_anuual int,
#Annual int;
select #months= DATEDIFF(MONTH, #startDate, #endDate);
select #quatorly= DATEDIFF(QUARTER, #startDate, #endDate);
select #Semi_anuual= DATEDIFF(QUARTER, #startDate, #endDate)/ 2;
select #Annual= DATEDIFF(YEAR, #startDate, #endDate);
WHILE (#endDate > #startDate)
begin
insert into #dates
select #months,#quatorly,#Semi_anuual,#Annual;
End;
return;
End;
Using a loop for this is about a awful for performance as you can get. You need to use a tally table for this type of thing. You need to start thinking in sets instead of row by row. Once you have a tally table (which I generated here with a cte), this is pretty simple.
create function MyFunctionThatGetsDatesByRange
(
#StartDate DATE
, #EndDate DATE
) RETURNS TABLE WITH SCHEMABINDING AS RETURN
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select DATEADD(DAY, N - 1, #StartDate) as date
, DATEPART(MONTH, DATEADD(DAY, N - 1, #StartDate)) as Month
, DATEPART(QUARTER, DATEADD(DAY, N - 1, #StartDate)) as Quarter
, CASE when DATEPART(QUARTER, DATEADD(DAY, N - 1, #StartDate)) <= 2 then 1 else 2 end as SemiAnnual
, DATEPART(YEAR, DATEADD(DAY, N - 1, #StartDate)) as Annual
from cteTally
where N <= DATEDIFF(DAY, #StartDate, #EndDate);
GO
declare #StartDate date = '2012-01-01'
, #EndDate date = '2015-09-09';
select *
from dbo.MyFunctionThatGetsDatesByRange(#StartDate, #EndDate)
hi thanks for your reply i achived that by using the below code.
create function func5_D_D
(#startDate date, #endDate date)
RETURNS #dates table
(months int,
quators int,
semi_annual int,
annual int)
As
Begin
WHILE #startDate <= #endDate
BEGIN
INSERT INTO #dates(months,quators,semi_annual,annual) values (MONTH(#startDate), datepart(qq,#startDate),
case when datepart(qq,#startDate) in (1,2) then 1 else
2 End,datepart(yyyy,#startdate))
SET #startDate = DATEADD(MONTH,1,#startDate)
END
return;
end;
Difference between two dates in X years Y Months and Z days (For example: Age in Years, Months and days)
We can use a script like below to get the difference between two dates in Years, Months and days.
Difference between two dates in X years Y Months and Z days (For example: Age in Years, Months and days)
We can use a script like below to get the difference between two
datDECLARE #FromDate DATETIME = '2010-01-01 23:59:59.000',
#ToDate DATETIME = '2015-01-02 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
s in Years, Months and days.

how view result date time datediff dateadd , but out-of-range value

i try compare date now and start date working from master_employee.
but i failed...
if at line i write
select #date = date_start
from Master_Employee
where id = '2'
its succes.
but i hope, can view all result in table Master_Employee.
can you help me ?
thank's very much..
DECLARE #date DATETIME
,#tmpdate DATETIME
,#years INT
,#months INT
,#days INT
SELECT #date = date_Start
FROM Master_Employee
SELECT #tmpdate = #date
SELECT #years = DATEDIFF(yyyy, #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(yyyy, #years, #tmpdate)
SELECT #months = DATEDIFF(mm, #tmpdate, GETDATE()) - CASE
WHEN DAY(#date) > DAY(GETDATE())
THEN 1
ELSE 0
END
SELECT #tmpdate = DATEADD(mm, #months, #tmpdate)
SELECT #days = DATEDIFF(dd, #tmpdate, GETDATE())
SELECT #years AS Years
,#months AS Months
,#days AS Dayss
,GETDATE() AS Date_Now
This will give you how many days, months, years have passed in aggregate for all employees, As far as I can tell this is what you are tying to do.
DECLARE #Today as datetime = CONVERT(Date,GETDATE())
SELECT SUM(DATEDIFF(day,ISNULL(convert(datetime,#date),Today),#Today)) [Days]
,SUM(DATEDIFF(MONTH,ISNULL(convert(datetime,#date),Today),#Today)) [Months]
,SUM(DATEDIFF(Year,ISNULL(convert(datetime,#date),Today(,#Today)) [Years]
FROM Master_Employee
The reason that
SELECT #date = date_Start
FROM Master_Employee
is failing is because you are trying to assign all the start dates to the same variable.
If you want separate lines for each employee try:
DECLARE #Today as datetime = CONVERT(Date,GETDATE())
SELECT Id
,SUM(DATEDIFF(day,ISNULL(convert(datetime,#date),Today),#Today)) [Days]
,SUM(DATEDIFF(MONTH,ISNULL(convert(datetime,#date),Today),#Today)) [Months]
,SUM(DATEDIFF(Year,ISNULL(convert(datetime,#date),Today),#Today)) [Years]
FROM Master_Employee
GROUP BY ID
Be careful, month and year can be misleading, if the person started 12/31/14 and you ran this on 1/1/15 you will see 1 day, 1 month, 1 year. You might be better off using only days and figuring your own math for how long that is...

How to display the exact age in Year Month Day format in SQL Server

I am stuck with my query. I have a table called Patient. In this table a column has patient DOB. Actually I want to display the exact age of the patient.
For example:
PatName DOB (MM/dd/yyyy) Age
a 06/02/1947 65 Years 1 Month/s 3 Days
b 07/10/1947 64 Years 11 Month/s 25 Days
c ----------- -----------------------
I want to display the age of the above format.
I have already googled about this but nobody helped.
If you have any query regarding this pls post that.
Thanks
Hi Check the query below.
--DROP TABLE patient
CREATE TABLE patient(PatName varchar(100),DOB date, Age varchar(100))
INSERT INTO patient
VALUES('a','06/02/1947',NULL),('b','07/10/1947',NULL),('c','12/21/1982',NULL)
;WITH CTE(PatName,DOB,years,months,days) AS
(SELECT PatName,DOB,DATEDIFF(yy,DOB,getdate()),DATEDIFF(mm,DOB,getdate()),DATEDIFF(dd,DOB,getdate()) FROM patient)
--SELECT * FROM CTE
SELECT PatName,DOB,
CAST(months/12 as varchar(5))+' Years'+CAST((months % 12) as varchar(5))+' month/s '+CAST(CASE WHEN DATEADD(MM,(months % 12),DATEADD(YY,(months/12),DOB)) <= GETDATE() then DATEDIFF(dd,DATEADD(MM,(months % 12),DATEADD(YY,(months/12),DOB)),GETDATE()) ELSE DAY(getdate()) END as varchar(5))+' days' as Age
FROM CTE
If you follow this link, you'll find a function doing exactly that:
create function dbo.F_AGE_YYYY_MM_DD
(
#START_DATE datetime,
#END_DATE datetime
)
returns varchar(10)
as
/*
Function: F_AGE_YYYY_MM_DD
This function calculates age in years, months and days
from #START_DATE through #END_DATE and
returns the age in format YYYY MM DD.
Years is the number of full years between #START_DATE and #END_DATE.
Months is the number of full months since the last full year anniversary.
Days is the number of days since the last full month anniversary.
*/
begin
declare #AGE varchar(10)
declare #AGE_IN_YEARS int
declare #AGE_IN_MONTHS int
declare #AGE_IN_DAYS int
-- Return null if #START_DATE > #END_DATE
if #START_DATE > #END_DATE begin return #AGE end
select
#AGE_IN_YEARS = AGE_IN_YEARS,
#AGE_IN_MONTHS = AGE_IN_MONTHS,
#AGE_IN_DAYS =
datediff(dd,
dateadd(mm,AGE_IN_MONTHS,
dateadd(yy,AGE_IN_YEARS,START_DATE))
,END_DATE)
from
(
select
AGE_IN_MONTHS =
case
when AnniversaryThisMonth <= END_DATE
then datediff(mm,dateadd(yy,AGE_IN_YEARS,START_DATE),END_DATE)
else datediff(mm,dateadd(yy,AGE_IN_YEARS,START_DATE),END_DATE)-1
end,
*
from
(
select
AGE_IN_YEARS =
case
when AnniversaryThisYear <= END_DATE
then datediff(yy,START_DATE,END_DATE)
else datediff(yy,START_DATE,END_DATE)-1
end,
*
from
(
select
AnniversaryThisYear =
dateadd(yy,datediff(yy,START_DATE,END_DATE),START_DATE),
AnniversaryThisMonth =
dateadd(mm,datediff(mm,START_DATE,END_DATE),START_DATE),
*
from
(
select START_DATE = dateadd(dd,datediff(dd,0,#START_DATE),0),
END_DATE = dateadd(dd,datediff(dd,0,#END_DATE),0)
) aaaa
) aaa
) aa
) a
select #AGE =
right('0000'+convert(varchar(4),#AGE_IN_YEARS),4) + ' ' +
right('00'+convert(varchar(4),#AGE_IN_MONTHS),2) + ' ' +
right('00'+convert(varchar(4),#AGE_IN_DAYS),2)
return #AGE
end
go
select [Age] = dbo.F_AGE_YYYY_MM_DD('2004-04-07','2006-02-03')
select [Age] = dbo.F_AGE_YYYY_MM_DD('2006-02-03','2006-02-03')
select [Age] = dbo.F_AGE_YYYY_MM_DD('2006-02-05','2006-02-03')
select [Age] = dbo.F_AGE_YYYY_MM_DD('1950-09-13', getdate())
DECLARE #date datetime, #tmpdate datetime, #years int, #months int, #days int
SELECT #date = '06/02/1947'
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())
print cast(#years as varchar(4)) + ' years, '+ cast (#months as varchar(2))+' months, '+ cast(#days as varchar(2)) + ' days'
Here is the solution
DATEDIFF(year, DOB, getdate()) - (CASE WHEN (DATEADD(year, DATEDIFF(year, DOB, getdate()), DOB)) > getdate() THEN 1 ELSE 0 END) as Years,
MONTH(getdate() - (DATEADD(year, DATEDIFF(year, DOB, getdate()), DOB))) - 1 as Month/s,
DAY(getdate() - (DATEADD(year, DATEDIFF(year, DOB, getdate()), DOB))) - 1 as Days