I thought the accurate year/month/day difference was the hard part. But if you need adding the strings around the values, just let me know.
The calcs are in the CROSS APPLYs, so that previously calc'd values can be used in subsequent calcs.
There are two ways to calc this: not counting the open day or counting the open day (second month): take your pick.
--not counting DateOpened separately
SELECT *
FROM ( VALUES (CAST('2017-11-04' AS date),CAST(GETDATE() AS date)),
('20170101', '20171231'),
('20170101', '20180101') )
AS test_data( DateOpened, DateClosed )
CROSS APPLY (
SELECT DATEDIFF(YEAR, DateOpened, DateClosed) -
CASE WHEN CONVERT(char(5), DateOpened, 1) >
CONVERT(char(5), DateClosed, 1) THEN 1 ELSE 0 END AS years_old
) AS year_calc
CROSS APPLY (
SELECT DATEDIFF(MONTH, DateOpened, DateClosed) - (years_old * 12) -
CASE WHEN DAY(DateOpened) > DAY(DateClosed) THEN 1 ELSE 0 END AS months_old
) AS month_calc
CROSS APPLY (
SELECT DATEDIFF(DAY, DATEADD(MONTH, years_old * 12 + months_old, DateOpened),
DateClosed) AS days_old
) AS day_calc
--counting DateOpened separately
SELECT *
FROM ( VALUES (CAST('2017-11-04' AS date),CAST(GETDATE() AS date)),
('20170101', '20171231'),
('20170101', '20180101') )
AS test_data( DateOpened, DateClosed )
CROSS APPLY (
SELECT DATEDIFF(YEAR, DateOpened, DATEADD(DAY, 1, DateClosed)) -
CASE WHEN CONVERT(char(5), DateOpened, 1) >
CONVERT(char(5), DATEADD(DAY, 1, DateClosed), 1) THEN 1 ELSE 0 END AS years_old
) AS year_calc
CROSS APPLY (
SELECT DATEDIFF(MONTH, DateOpened, DATEADD(DAY, 1, DateClosed)) - (years_old * 12) -
CASE WHEN DAY(DateOpened) > DAY(DateClosed) THEN 1 ELSE 0 END AS months_old
) AS month_calc
CROSS APPLY (
SELECT DATEDIFF(DAY, DATEADD(MONTH, years_old * 12 + months_old, DateOpened),
DATEADD(DAY, 1, DateClosed)) AS days_old
) AS day_calc