Як обчислити вік (у роках), виходячи з дати народження та getDate ()


171

У мене є таблиця з переліком людей разом з їх датою народження (зараз nvarchar (25))

Як я можу це перетворити на дату, а потім обчислити їх вік у роках?

Мої дані виглядають так

ID    Name   DOB
1     John   1992-01-09 00:00:00
2     Sally  1959-05-20 00:00:00

Я б хотів побачити:

ID    Name   AGE  DOB
1     John   17   1992-01-09 00:00:00
2     Sally  50   1959-05-20 00:00:00

16
Чому ви зберігаєте значення дат у вигляді рядків, використовуючи nvarchar (25), а не використовуючи нативну дату бази даних або тип дати?
Jesper

Питання позначено 2005, а не 2008, тому рідний тип "Дата" недоступний, але, безумовно, дата, і це може бути аргументовано SmallDateTime, оскільки точність вам не потрібна.
Андрій

Привіт, причина збереження дат як varchar полягає в тому, що я імпортую це з не-серверної схеми сервера, були деякі проблеми, що імпортували їх як дата (та інші формати дат) і varchar перетворили нормально
Джиммі

7
@ James.Elsey, тож у вас виникли проблеми з імпортом, і як результат усі дати дійсні? Ніколи не може бути впевнений, якщо ви не використовуєте дату або малі дати, за допомогою varchar, ви можете привезти їх на роботу, але у вас виникнуть інші проблеми. Крім того, я ніколи не зберігаю вік, він змінюється щодня, використовую View
KM.

@KM Так, виникла проблема з імпортом цих даних як дати, єдиним життєздатним рішенням на той час було імпортувати їх як nvarchars. Цей вибір стане частиною нічної роботи, тому зберігання віку не повинно бути проблемою
Джиммі

Відповіді:


256

Існують проблеми з високосним роком / днями та наступним методом, див. Оновлення нижче:

спробуйте це:

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

ВИХІД:

AgeYearsDecimal                         AgeYearsIntRound AgeYearsIntTrunc
--------------------------------------- ---------------- ----------------
17.767054                               18               17

(1 row(s) affected)

ОНОВЛЕННЯ ось кілька більш точних методів:

НАЙКРАЩИЙ МЕТОД ЗА ГОДИНИ В ІНТ

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

ви можете змінити вище 10000 на 10000.0та отримати десяткові знаки, але це буде не так точно, як метод нижче.

НАЙКРАЩИЙ МЕТОД ЗА РОКІВ В ДЕКІМАЛІ

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

24
Це також не є точним рішенням. Якщо я вважаю, що моя @dob є '1986-07-05 00:00:00', і я виконаю цю функцію (використовую іншу змінну замість GETDATE()) '2013-07-04 23:59:59', вона говорить, що я мені 27, а в цей момент я ще не. Приклад коду: declare @startDate nvarchar(100) = '1986-07-05 00:00:00' declare @endDate nvarchar(100) = '2013-07-04 23:59:59' SELECT DATEDIFF(hour,@startDate,@endDate)/8766.0 AS AgeYearsDecimal ,CONVERT(int,ROUND(DATEDIFF(hour,@startDate,@endDate)/8766.0,0)) AS AgeYearsIntRound ,DATEDIFF(hour,@startDate,@endDate)/8766 AS AgeYearsIntTrunc
bartlaarhoven

20
Це не точно, оскільки передбачає 8766 годин на рік, що складає 365,25 днів. Оскільки немає 365,25 днів, це буде неправильно біля дати народження людини частіше, ніж це правильно. Цей метод все ще буде більш точним.
шматочки бекону

1
Другий коментар @Bacon Bits - це часто буде неправильним, коли поточна дата поруч з датою народження людини.
спалах

2
Я думаю, що перший блок тексту робить цю відповідь заплутаною. Якщо ваш оновлений метод не має проблеми з високосними роками, я б радив (якщо ви насправді хочете зберегти його) перенести його внизу вашої відповіді.
ajbeaven

1
Якщо ви хочете EXACT розрахунок, то DATEDIFF не робитиме це @ShailendraMishra, тому що він наближається днів, і т.д .. Наприклад, select datediff(year, '2000-01-05', '2018-01-04')повертає 18, а не 17 як слід. Я використав приклад вище в заголовку "НАЙКРАЩИЙ МЕТОД ЗА РОКІВ В ІНТ", і він відмінно працює. Дякую!
openwonk

132

Треба викинути цю туди. Якщо ви перетворите дату за допомогою стилю 112 (yyyymmdd) в число, ви можете використовувати обчислення, як це ...

(yyyyMMdd - yyyyMMdd) / 10000 = різниця за повні роки

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

вихід

20091015    19800420    290595  29

14
Це майже магічно в тому, як він вирішує всі проблеми високосного року. Можливо, варто відзначити, що 112 - це спеціальний номер для функції CONVERT, який форматує дату як yyyymmdd. Це, мабуть, не очевидно для всіх, коли на це дивишся.
Дерек Томес

5
Ви геній!
Еркан

Моя команда зіткнулася з проблемою, коли дата, яку ми використовували для пошуку віку, була в той самий день, що і дата, з якою ми порівнюємо її. Ми помічали, що коли вони будуть в той самий день (і якщо вік буде непарним), вік знищиться на одиницю. Це спрацювало чудово!
The Sheek Geek

1
Це правильна відповідь - будь ласка, позначте її як таку.
Snympi

4
Найпростіший / найкоротший код для цього самого методу обчислення в SQL Server 2012+code: SELECT [Age] = (0+ FORMAT(@as_of,'yyyyMMdd') - FORMAT(@bday,'yyyyMMdd') ) /10000 --The 0+ part tells SQL to calc the char(8) as numbers
ukgav

44

Я використовував цей запит у нашому виробничому коді майже 10 років:

SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(Date_of_birth AS INTEGER)) / 365.25) AS Age

6
Це непогано, але це не на 100%, 2007/10/16 повідомить про 2-річний вік 15.10.2009
Андрій

4
До, ми пропускаємо очевидне, це вже після середини дня, getdate повертає int, тому буде, звичайно, округлення. Я копію вставив вашу відповідь і запустив її, тому автоматично використовувався getdate, а не буквальний.
Андрій

2
Елегантний і простий. Дякую!
Вільям МБ

9
Якщо ми говоримо про вік людини, то слід обчислити його так, як люди обчислюють вік. Це не має нічого спільного з тим, як швидко рухається земля і все, що стосується календаря. Кожен раз, коли минає той самий місяць і день, як дата народження, ви збільшуєте вік на 1. Це означає, що наступне найточніше, оскільки воно відображає, що означають люди, коли вони говорять про "вік":DATEDIFF(yy, @BirthDate, GETDATE()) - CASE WHEN (MONTH(@BirthDate) >= MONTH(GETDATE())) AND DAY(@BirthDate) > DAY(GETDATE()) THEN 1 ELSE 0 END
Беконові шматочки

5
Вибачте, що синтаксис неправильний. CASE WHEN (MONTH(@date) > MONTH(GETDATE())) OR (MONTH(@date) = MONTH(GETDATE()) AND DAY(@date) > DAY(GETDATE())) THEN 1 ELSE 0 END
Бакони з беконом

31

Тому багато з перерахованих вище рішень неправильні. DateDiff (yy, @ Dob, @PassedDate) не враховуватиме місяць та день обох дат. Також беруть деталі дротиків і порівнюють їх, лише якщо вони належним чином упорядковані.

СЛОВНИЙ КОД працює і є ДУЖЕ ПРОСТО:

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

Чому ви множите на 100? Це працює для мене, оскільки я намагаюся копіювати в базі даних те, що існує в нашій бібліотеці кодів, але я не зміг пояснити вашу функцію. Це може бути дурним питанням :)
Jen

6
Дякую! Саме такий код я очікував тут. Це єдиний правильний код у цій темі без (потворних) рядкових перетворень! @Jen Це займає місяць і день DoB (наприклад, 25 вересня) і перетворює його на ціле число 0925(або 925). Це робиться так само з поточною датою (як, наприклад, 16 грудня 1216), а потім перевіряється, чи вже минуло ціле значення DoB. Щоб створити це ціле число, місяць слід помножити на 100.
bartlaarhoven

Дякую @bartlaarhoven :)
Джен

Я лише зазначу, що, хоча це не дозволяє перетворення рядків, натомість це робить багато кастингу. Моє тестування показує, що це не суттєво швидше, ніж відповідь dotjoe , і код є більш багатослівним.
Стриптинг-воїн

прийнята відповідь має набагато простішу відповідь INT:(CONVERT(int,CONVERT(char(8),@Now,112))-CONVERT(char(8),@Dob,112))/10000
KM.

19

Вам потрібно розглянути спосіб обходу датованої команди.

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>

Який я тут адаптував .

Зауважимо, що 28 лютого він вважатиме днем ​​народження вистрибування в нестримні роки, наприклад, особа, яка народилася 29 лютого 2020 року, вважатиметься 1-річною на 28 лютого 2021 року замість 01 березня 2021 року.


@Andrew - Виправлено - я пропустив одну із замін
Ед Гарпер

1
Спрощена версіяSELECT DATEDIFF(year, DOB, getdate()) + CASE WHEN (DATEADD(year,DATEDIFF(year, DOB, getdate()) , DOB) > getdate()) THEN - 1 ELSE 0 END)
Пітер

Це правильний підхід; Я не розумію, чому на хаків так сильно заважають.
Салман А

8

РЕДАКТУЙТЕ: ЦЕ ВІДПОВІДЬ НЕПРАВИЛЬНА. Я залишаю це тут як попередження для тих, хто спокусився використовувати dayofyear, з подальшим редагуванням наприкінці.


Якщо, як і я, ви не хочете ділитися на дробові дні чи ризикувати помилки округлення / високосного року, я аплодую коментарі @Bacon Bits у публікації вище https://stackoverflow.com/a/1572257/489865, де він говорить:

Якщо ми говоримо про вік людини, то слід обчислити його так, як люди обчислюють вік. Це не має нічого спільного з тим, як швидко рухається земля і все, що стосується календаря. Щоразу, коли минає той самий місяць і день, як дата народження, ви збільшуєте вік на 1. Це означає, що наступне є найбільш точним, оскільки воно відображає, що означають люди, коли вони говорять "вік".

Потім він пропонує:

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

Тут є кілька пропозицій, що стосуються порівняння місяця та дня (а деякі його помиляються, не враховуючи ORяк тут правильно!). Але ніхто не запропонував dayofyear, що здається таким простим і набагато коротшим. Я пропоную:

DATEDIFF(year, @date, GETDATE()) -
CASE WHEN DATEPART(dayofyear, @date) > DATEPART(dayofyear, GETDATE()) THEN 1 ELSE 0 END

[Примітка: Ніде в SQL BOL / MSDN немає того, що DATEPART(dayofyear, ...)повертає насправді документально! Я розумію, це число в діапазоні 1--366; найголовніше, що це не змінюється за локальною ознакою відповідно до DATEPART(weekday, ...)& SET DATEFIRST.]


EDIT: Чому dayofyearйде не так : Як прокоментував користувач @AeroX, якщо дата народження / початку закінчується після лютого у не високосний рік, вік збільшується на день раніше, коли поточна / кінцева дата - високосний рік, наприклад '2015-05-26', '2016-05-25'дає вік 1 року, коли він все ще повинен бути 0. Порівнювати dayofyearрізні роки очевидно небезпечно. Тож використовувати MONTH()і DAY()потрібно зрештою.


Це слід проголосувати або навіть позначити як відповідь. Він короткий, елегантний і логічно правильний.
z00l

1
Для всіх, хто народився після лютого, їх вік збільшується на один день раніше, на кожен високосний рік, використовуючи DayOfYearметод.
AeroX

4
@AeroX Дякуємо, що помітили цей недолік. Я вирішив залишити своє рішення в якості попередження для всіх, хто може або використовував dayofyear, але чітко відредагований, щоб показати, чому воно йде не так. Я сподіваюся, що це підходить.
JonBrave

5

Оскільки не існує однієї простої відповіді, яка завжди відповідає правильному віку, ось що я придумав.

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 

При цьому виходить різниця в році між датою народження та поточною датою. Потім вона віднімає рік, якщо дата народження ще не минула.

Будьте точні постійно - незалежно від високосних років або наближення до дати народження.

Найкраще - немає функції.


3
SELECT ID,
Name,
DATEDIFF(yy,CONVERT(DATETIME, DOB),GETDATE()) AS AGE,
DOB
FROM MyTable

1
Ви хочете отримати getdate як другий аргумент, а не перший, інакше ви отримаєте від'ємні результати чисел та раундів дати, тому виберіть dateiff (yy, '20081231', getdate ()) повідомлять про вік 1 року, але їм буде лише 10 місяців .
Андрій

1
Цей підрахунок дає неправильні підрахунки для людей, у яких цього року ще не було народження.

3

А як на рахунок:

DECLARE @DOB datetime
SET @DOB='19851125'   
SELECT Datepart(yy,convert(date,GETDATE())-@DOB)-1900

Хіба це не уникне всіх проблем із округленням, обрізанням та набором проблем?


Ваш розрахунок не точний. Наприклад: це не вдається, якщо ви приймаєте '1986-07-05 00:00:00'на DOB і '2013-07-04 23:59:59'на поточний час.
drinovc

@ub_coding Чи пропонуєте ви, відповідь або задаєте інше запитання?
Аарон С

це: DECLARE @DOB datetime SET @ DOB = '19760229' SELECT Datepart (yy, convert (datetime, '19770228') - @ DOB) -1900 = 1 Основна проблема - розрив fev 29 для більшості рішень, що пояснює обрізання округлення тощо. .
Леонардо Маркес де Суза

3

Я вважаю, що це схоже на інші, розміщені тут .... але це рішення працювало на приклад високосного року 29.02.1976 по 01.03.2011, а також працював у справі перший рік .. як 07/04 / 2011 р. По 07.03.2012 р., Останній розміщений про рішення високосного року, не працював для цього випадку використання першого року.

SELECT FLOOR(DATEDIFF(DAY, @date1 , @date2) / 365.25)

Знайдено тут .


3

Просто перевірте, чи можлива відповідь нижче.

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        
 )

2
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
)

джерело: http://beginsql.wordpress.com/2012/04/26/how-to-calculate-age-in-sql-server/


Більш короткий спосіб зробити це в SQL Server 2012+ полягає в наступному, і уникнути перетворення на 112, а підлога не потрібна:code: SELECT [Age] = (0+ FORMAT(@ToDate,'yyyyMMdd') - FORMAT(@DOB,'yyyyMMdd') ) /10000
ukgav

2

Я багато думав і шукав про це, і у мене є 3 рішення, які

  • правильно розрахувати вік
  • короткі (в основному)
  • є (в основному) дуже зрозумілими.

Ось значення тестування:

DECLARE @NOW DATETIME = '2013-07-04 23:59:59' 
DECLARE @DOB DATETIME = '1986-07-05' 

Рішення 1: Я знайшов такий підхід в одній бібліотеці js. Це мій улюблений.

DATEDIFF(YY, @DOB, @NOW) - 
  CASE WHEN DATEADD(YY, DATEDIFF(YY, @DOB, @NOW), @DOB) > @NOW THEN 1 ELSE 0 END

Це фактично додає різницю років у DOB, і якщо вона більша за поточну дату, то віднімаємо один рік. Просте так? Єдине, що тут різняться різниці в роках.

Але якщо вам не потрібно використовувати його вбудовано, ви можете написати це так:

DECLARE @AGE INT = DATEDIFF(YY, @DOB, @NOW)
IF DATEADD(YY, @AGE, @DOB) > @NOW
SET @AGE = @AGE - 1

Рішення 2: Цей оригінал я скопіював із @ bacon-бітів. Це найлегше зрозуміти, але трохи довго.

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

Це в основному підрахунок віку, як ми люди.


Рішення 3: Мій друг переробив це на це:

DATEDIFF(YY, @DOB, @NOW) - 
  CEILING(0.5 * SIGN((MONTH(@DOB) - MONTH(@NOW)) * 50 + DAY(@DOB) - DAY(@NOW)))

Цей найкоротший, але його важче зрозуміти. 50є лише вагою, тому різниця в дні важлива лише тоді, коли місяці однакові. SIGNФункція полягає в перетворенні будь-якого значення, яке воно отримує, в -1, 0 або 1. CEILING(0.5 *таке ж, як, Math.max(0, value)але такого немає в SQL.


1
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

1
select floor((datediff(day,0,@today) - datediff(day,0,@birthdate)) / 365.2425) as age

Тут є багато 365,25 відповідей. Згадайте, як визначаються високосні роки:

  • Кожні чотири роки
    • крім кожні 100 років
      • крім кожні 400 років

Відмінна відповідь. Для тих, хто цікавиться тут, є пояснення того, чому 365.2425 є правильним значенням для використання: grc.nasa.gov/WWW/k-12/Numbers/Math/Mathematical_Thinking/…
vvvv4d

0

Як щодо цього:

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

0

Спробуйте це

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'

0

Спробуйте це рішення:

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

0

Це правильно вирішить проблеми з днем ​​народження та округленням:

DECLARE @dob  datetime
SET @dob='1992-01-09 00:00:00'

SELECT DATEDIFF(YEAR, '0:0', getdate()-@dob)

2
Не обробляти високосні правильно ВИБРАТИ DATEDIFF (YEAR, '0: 0', новонавернений (DateTime, '2014-02-28') -'2012-02-29 ') дає 2, але повинен бути тільки один
Пітер Керр

0

Рішення Еда Гарпера - це найпростіший із мене знайдених, який ніколи не повертає неправильної відповіді, коли місяць і день двох дат один від одного. Я вніс невелику модифікацію для подолання негативних віків

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

0

Відповідь, позначена правильною, наближається до точності, але вона не відповідає наступному сценарію - де рік народження - це високосний рік та день після лютого місяця

declare @ReportStartDate datetime = CONVERT(datetime, '1/1/2014'),
@DateofBirth datetime = CONVERT(datetime, '2/29/1948')

FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8766)


АБО

FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8765.82) -- Divisor is more accurate than 8766

- Наступне рішення дає мені більш точні результати.

FLOOR(DATEDIFF(YEAR,@DateofBirth,@ReportStartDate) - (CASE WHEN DATEADD(YY,DATEDIFF(YEAR,@DateofBirth,@ReportStartDate),@DateofBirth) > @ReportStartDate THEN 1 ELSE 0 END ))

Він працював майже у всіх сценаріях, враховуючи високосний рік, дату 29 лютого тощо.

Будь ласка, виправте мене, якщо в цій формулі є лазівка.


Заключна формула майже точна, як у цій відповіді stackoverflow.com/a/1572235/168747 . Але той, який тут менш читабельний, містить непотрібне floor.
Марек

0
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

0

Ось як я обчислюю вік за датою народження та поточною датою.

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

0
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

-1: Буде помилятися будь-коли, month(compare) > month(dob)але day(compare) < day(dob), напр select dbo.AgeAtDate('2000-01-14', '2016-02-12').
JonBrave

Ви маєте рацію, дякую за цей випадок, оновили функцію
Вова

0
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

0

А як щодо рішення з лише функціями дати, а не з математикою, не турбує високосний рік

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

0

Спробувавши МНОГО методів, це працює 100% часу, використовуючи сучасну функцію MS SQL FORMAT замість перетворення в стиль 112. Будь-яка робота, але це найменший код.

Чи може хтось знайти поєднання дати, яке не працює? Я не думаю, що є такий :)

--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

-2

Ми використовували щось подібне тут, але потім брали середній вік:

ROUND(avg(CONVERT(int,DATEDIFF(hour,DOB,GETDATE())/8766.0)),0) AS AverageAge

Зауважте, КРУГА знаходиться зовні, а не всередині. Це дозволить AVG бути більш точним, і ми ОБРАЗУЄМО лише один раз. Зробити це теж швидше.


-2
select DATEDIFF(yy,@DATE,GETDATE()) -
case when DATEPART(mm,GETDATE())*100+DATEPART(dd,GETDATE())>=
DATEPART(mm,@DATE)*100+DATEPART(dd,@DATE) THEN 0
ELSE 1 END 

-2
SELECT CAST(DATEDIFF(dy, @DOB, GETDATE()+1)/365.25 AS int)

Я бачу голоси, але я не бачу прикладів, які підтверджують, що це порушено.
Алекс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.