Comment calculer l'âge (en années) en fonction de la date de naissance et de getDate ()

172

J'ai un tableau répertoriant les personnes avec leur date de naissance (actuellement un nvarchar (25))

Comment puis-je convertir cela en une date, puis calculer leur âge en années?

Mes données se présentent comme suit

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

J'aimerais voir:

ID    Name   AGE  DOB
1     John   17   1992-01-09 00:00:00
2     Sally  50   1959-05-20 00:00:00
Jimmy
la source
16
Pourquoi stockez-vous les valeurs de date sous forme de chaînes à l'aide de nvarchar (25) au lieu d'utiliser le type natif de date ou d'heure de la base de données?
Jesper
La question est étiquetée 2005 et non 2008, donc le type natif 'Date' n'est pas disponible, mais définitivement une date / heure, et il pourrait être argumenté SmallDateTime puisque vous n'avez pas besoin de la précision.
Andrew
Salut, la raison pour laquelle les dates sont conservées en tant que varchar est que j'importe cela à partir d'un schéma de serveur non SQL, il y a eu des problèmes pour les importer en tant que datetime (et les autres formats de date) et varchar converti ok
Jimmy
7
@ James.Elsey, vous avez donc eu des problèmes d'importation et, par conséquent, toutes les dates sont-elles valides? ne peut jamais être sûr à moins d'utiliser un datetime ou smalldatetime, avec varchar, vous pouvez faire fonctionner votre importation, mais avoir d'autres problèmes sur toute la ligne. De plus, je ne stockais jamais l'âge, cela change chaque jour, utilisez une vue
KM.
@KM Oui, il y avait un problème lors de l'importation de ces données sous forme de date, la seule solution viable à l'époque était de les importer en tant que nvarchars. Cette sélection fera partie d'un travail de nuit, donc stocker l'âge ne devrait pas être un problème
Jimmy

Réponses:

256

Il y a des problèmes avec les années / jours bissextiles et la méthode suivante, voir la mise à jour ci-dessous:

essaye ça:

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

PRODUCTION:

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

(1 row(s) affected)

MISE À JOUR voici quelques méthodes plus précises:

MEILLEURE MÉTHODE POUR LES ANNÉES EN 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

vous pouvez changer ci - dessus 10000pour 10000.0et obtenir des décimales, mais il ne sera pas aussi précis que la méthode ci - dessous.

MEILLEURE MÉTHODE POUR LES ANNÉES EN DÉCIMAL

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
KM.
la source
24
Ce n'est pas non plus une solution exacte. Si je prends mon propre @dob pour être '1986-07-05 00:00:00' et que j'exécuterais ceci (utiliser une autre variable au lieu de GETDATE()) le '2013-07-04 23:59:59', il dit que je J'ai 27 ans, alors qu'à ce moment, je ne suis pas encore. Exemple de code: 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
Ce n'est pas exact car cela suppose 8766 heures par an, ce qui correspond à 365,25 jours. Puisqu'il n'y a pas d'années avec 365,25 jours, cela sera incorrect près de la date de naissance de la personne plus souvent que correct. Cette méthode sera toujours plus précise.
Bacon Bits
1
Deuxième commentaire @Bacon Bits - ce sera souvent faux lorsque la date actuelle est proche de la date de naissance d'une personne.
flash le
2
Je pense que le premier bloc de texte rend cette réponse déroutante. Si votre méthode mise à jour ne présente pas le problème des années bissextiles, je suggérerais (si vous voulez vraiment la conserver) de la déplacer au bas de votre réponse.
ajbeaven
1
Si vous voulez un calcul EXACT , alors DATEDIFF ne le fera pas @ShailendraMishra, car il se rapproche des jours, etc. Par exemple, select datediff(year, '2000-01-05', '2018-01-04')renvoie 18 et non 17 comme il se doit. J'ai utilisé l'exemple ci-dessus sous la rubrique "MEILLEURE MÉTHODE POUR LES ANNÉES EN INT" et cela fonctionne parfaitement. Merci!
openwonk
133

Je dois jeter celui-ci là-bas. Si vous convertissez la date en utilisant le style 112 (aaaammjj) en un nombre, vous pouvez utiliser un calcul comme celui-ci ...

(aaaaMMjj - aaaaMMjj) / 10000 = différence en années complètes

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

production

20091015    19800420    290595  29
dotjoe
la source
14
C'est presque magique dans la façon dont cela résout tous les problèmes des années bissextiles. Il peut être intéressant de noter que 112 est un numéro spécial pour la fonction CONVERT qui formate la date comme aaaammjj. Ce n'est peut-être pas évident pour tout le monde quand vous le regardez.
Derek Tomes
5
Tu es un génie!
ercan
Mon équipe rencontrait un problème lorsque la date que nous utilisions pour trouver l'âge était le même jour que la date à laquelle nous le comparons. Nous remarquions que lorsqu'ils étaient le même jour (et si l'âge allait être étrange), l'âge serait de un. Cela a parfaitement fonctionné!
The Sheek Geek
1
C'est la bonne réponse - veuillez la marquer comme telle.
Snympi
4
Le code le plus simple / le plus court pour cette méthode de calcul identique dans SQL Server 2012+ estcode: 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

J'utilise cette requête dans notre code de production depuis près de 10 ans:

SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(Date_of_birth AS INTEGER)) / 365.25) AS Age
J__
la source
6
Ce n'est pas mal, mais ce n'est pas 100%, 2007/10/16 rapportera un âge de 2 ans le 15/10/2009
Andrew
4
Doh, nous manquons l'évidence, c'est après midi, getdate retourne un int donc sera arrondi bien sûr. J'ai copié-collé votre réponse et l'ai exécutée, donc automatiquement utilisé getdate, pas le littéral.
Andrew
2
Élégant et simple. Merci!
William MB
9
Si nous parlons de l'âge humain, vous devez le calculer comme les humains calculent l'âge. Cela n'a rien à voir avec la vitesse à laquelle la terre se déplace et tout à voir avec le calendrier. Chaque fois que le même mois et le même jour s'écoulent que la date de naissance, vous incrémentez l'âge de 1. Cela signifie que ce qui suit est le plus précis car il reflète ce que les humains veulent dire quand ils disent «âge»:DATEDIFF(yy, @BirthDate, GETDATE()) - CASE WHEN (MONTH(@BirthDate) >= MONTH(GETDATE())) AND DAY(@BirthDate) > DAY(GETDATE()) THEN 1 ELSE 0 END
Bacon Bits
5
Désolé, cette syntaxe est erronée. CASE WHEN (MONTH(@date) > MONTH(GETDATE())) OR (MONTH(@date) = MONTH(GETDATE()) AND DAY(@date) > DAY(GETDATE())) THEN 1 ELSE 0 END
Bacon Bits
31

La plupart des solutions ci-dessus sont donc erronées. DateDiff (yy, @ Dob, @PassedDate) ne tiendra pas compte du mois et du jour des deux dates. Prendre également les pièces de fléchettes et comparer ne fonctionne que si elles sont correctement ordonnées.

LE CODE SUIVANT FONCTIONNE ET EST TRÈS 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
user2634514
la source
Pourquoi multipliez-vous par 100? Cela fonctionne pour moi car j'essaie de répliquer dans la base de données ce qui existe dans notre bibliothèque de code - mais je ne pouvais pas expliquer votre fonction. Cela pourrait être une question stupide :)
Jen
6
Merci! Exactement le code que j'attendais ici. C'est le seul code exactement correct dans ce thread sans (moche) transformations de chaînes! @Jen Il prend le mois et le jour de la DoB (comme le 25 septembre) et le transforme en une valeur entière 0925(ou 925). Il fait la même chose avec la date actuelle (comme le 16 décembre devient 1216) et vérifie ensuite si la valeur entière DoB est déjà passée. Pour créer cet entier, le mois doit être multiplié par 100.
bartlaarhoven
Merci @bartlaarhoven :)
Jen
Je mentionnerai simplement que même si cela évite les transformations de chaînes, cela fait beaucoup de cast à la place. Mes tests montrent que ce n'est pas beaucoup plus rapide que la réponse de dotjoe , et le code est plus détaillé.
StriplingWarrior
la réponse acceptée a une réponse INT beaucoup plus simple:(CONVERT(int,CONVERT(char(8),@Now,112))-CONVERT(char(8),@Dob,112))/10000
KM.
19

Vous devez tenir compte de la manière dont la commande dateiff tourne.

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>

Ce que j'ai adapté d' ici .

Notez qu'il considérera le 28 février comme l'anniversaire d'un bondissant pour les années non bissextiles, par exemple, une personne née le 29 février 2020 sera considérée comme âgée de 1 an le 28 février 2021 au lieu du 01 mars 2021.

Ed Harper
la source
@Andrew - Corrigé - J'ai raté l'une des substitutions
Ed Harper
1
Version simplifiéeSELECT DATEDIFF(year, DOB, getdate()) + CASE WHEN (DATEADD(year,DATEDIFF(year, DOB, getdate()) , DOB) > getdate()) THEN - 1 ELSE 0 END)
Peter
C'est la bonne approche; Je ne comprends pas pourquoi les hacks sont autant votés.
Salman A
8

MODIFIER: CETTE RÉPONSE EST INCORRECTE. Je le laisse ici comme un avertissement à toute personne tentée d'utiliser dayofyear, avec une autre modification à la fin.


Si, comme moi, vous ne voulez pas diviser par fractions de jours ou risquer des erreurs d'arrondi / d'année bissextile, j'applaudis le commentaire de @Bacon Bits dans un message ci-dessus https://stackoverflow.com/a/1572257/489865 où il dit:

Si nous parlons de l'âge humain, vous devez le calculer comme les humains calculent l'âge. Cela n'a rien à voir avec la vitesse à laquelle la terre se déplace et tout à voir avec le calendrier. Chaque fois que le même mois et le même jour s'écoulent que la date de naissance, vous incrémentez l'âge de 1. Cela signifie que ce qui suit est le plus précis car il reflète ce que les humains veulent dire quand ils disent «âge».

Il propose ensuite:

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

Il y a plusieurs suggestions ici impliquant la comparaison du mois et du jour (et certains se trompent, sans tenir compte du ORaussi correctement ici!). Mais personne n'a offert dayofyear, ce qui semble si simple et beaucoup plus court. J'offre:

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

[Note: Nulle part dans SQL BOL / MSDN ce qui DATEPART(dayofyear, ...)renvoie réellement documenté! Je crois comprendre que c'est un nombre compris entre 1 et 366; plus important encore, il ne change pas selon les paramètres régionaux selon DATEPART(weekday, ...)& SET DATEFIRST.]


EDIT: Pourquoi se dayofyearpasse- t -il mal ? Comme l'a commenté l'utilisateur @AeroX, si la date de naissance / début est après février dans une année non bissextile, l'âge est incrémenté un jour plus tôt lorsque la date actuelle / de fin est une année bissextile, par exemple '2015-05-26', '2016-05-25'donne un l'âge de 1 alors qu'il devrait encore être de 0. La comparaison dayofyearde différentes années est clairement dangereuse. Donc utiliser MONTH()et DAY()est nécessaire après tout.

JonBrave
la source
Cela devrait être voté ou même marqué comme la réponse. Il est court, élégant et logiquement correct.
z00l
1
Pour toute personne née après février, son âge est incrémenté un jour avant chaque année bissextile en utilisant la DayOfYearméthode.
AeroX
4
@AeroX Merci d'avoir repéré cette faille. J'ai décidé de laisser ma solution comme un avertissement à toute personne qui pourrait ou a utilisé dayofyear, mais clairement éditée pour montrer pourquoi elle ne va pas. J'espère que cela convient.
JonBrave
5

Puisqu'il n'y a pas une réponse simple qui donne toujours l'âge correct, voici ce que j'ai trouvé.

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 

Cela obtient la différence d'année entre la date de naissance et la date actuelle. Ensuite, il soustrait un an si la date de naissance n'est pas encore dépassée.

Précis à tout moment - indépendamment des années bissextiles ou de la proximité de la date de naissance.

Le meilleur de tous - aucune fonction.

Poing de Hanovre
la source
3
SELECT ID,
Name,
DATEDIFF(yy,CONVERT(DATETIME, DOB),GETDATE()) AS AGE,
DOB
FROM MyTable
flayto
la source
1
Vous voulez getdate comme deuxième argument et non comme premier sinon vous obtenez des résultats numériques négatifs et des arrondis datés, donc sélectionnez datéiff (yy, '20081231', getdate ()) indiquera un âge de 1, mais ils n'auraient que 10 mois .
Andrew
1
Ce calcul donne des calculs incorrects pour les personnes qui n'ont pas encore fêté leur anniversaire cette année.
3

Qu'en est-il de:

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

Cela n'éviterait-il pas tous ces problèmes d'arrondi, de troncature et de réglage?

ub_coding
la source
Votre calcul n'est pas précis. Par exemple: il échoue si vous prenez '1986-07-05 00:00:00'pour DOB et '2013-07-04 23:59:59'pour l'heure actuelle.
drinovc
@ub_coding Proposez-vous et répondez-vous ou posez-vous une autre question?
Aaron C
ceci: DECLARE @DOB datetime SET @ DOB = '19760229' SELECT Datepart (yy, convert (datetime, '19770228') - @ DOB) -1900 = 1 le problème principal est un écart de 29 fév pour la plupart des solutions, cela explique l'arrondi tronqué, etc. .
Leonardo Marques de Souza
3

Je crois que c'est similaire à d'autres postés ici .... mais cette solution a fonctionné pour les exemples d'année bissextile 29/02/1976 au 03/01/2011 et a également fonctionné pour le cas pour la première année .. comme 07/04 / 2011 au 07/03/2012 que le dernier a publié sur la solution des années bissextiles n'a pas fonctionné pour ce cas d'utilisation de la première année.

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

Trouvé ici .

lepert
la source
3

Vérifiez simplement si la réponse ci-dessous est réalisable.

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        
 )
Gopakumar N.Kurup
la source
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
)

source: http://beginsql.wordpress.com/2012/04/26/how-to-calculate-age-in-sql-server/

celsowm
la source
Une façon plus courte de faire cela dans SQL Server 2012+ est la suivante, et évite les conversions en 112 et le sol n'est pas requis:code: SELECT [Age] = (0+ FORMAT(@ToDate,'yyyyMMdd') - FORMAT(@DOB,'yyyyMMdd') ) /10000
ukgav
2

J'ai beaucoup réfléchi et cherché à ce sujet et j'ai 3 solutions qui

  • calculer l'âge correctement
  • sont courts (principalement)
  • sont (pour la plupart) très compréhensibles.

Voici les valeurs de test:

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

Solution 1: J'ai trouvé cette approche dans une bibliothèque js. C'est mon prefere.

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

Cela ajoute en fait une différence en années à la date de naissance et si elle est supérieure à la date actuelle, elle soustrait un an. Simple non? La seule chose est que la différence d'années est ici dupliquée.

Mais si vous n'avez pas besoin de l'utiliser en ligne, vous pouvez l'écrire comme ceci:

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

Solution 2: Celui-ci que j'ai copié à l'origine à partir de @ bacon-bits. C'est le plus simple à comprendre mais un peu 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

Il s'agit essentiellement de calculer l'âge comme nous le faisons les humains.


Solution 3: mon ami l'a remanié en ceci:

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

Celui-ci est le plus court mais il est le plus difficile à comprendre. 50est juste un poids, donc la différence de jour n'est importante que lorsque les mois sont identiques. SIGNLa fonction est pour transformer n'importe quelle valeur qu'elle obtient en -1, 0 ou 1. CEILING(0.5 *est la même que Math.max(0, value)mais il n'y a rien de tel en SQL.

drinovc
la source
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
Viswa Teja Kuncham
la source
1
select floor((datediff(day,0,@today) - datediff(day,0,@birthdate)) / 365.2425) as age

Il y a beaucoup de 365,25 réponses ici. Rappelez-vous comment les années bissextiles sont définies:

  • Tous les quatre ans
    • sauf tous les 100 ans
      • sauf tous les 400 ans
Brianary
la source
Excellente réponse. Pour ceux qui sont curieux, voici une explication de la raison pour laquelle 365.2425 est la valeur correcte à utiliser: grc.nasa.gov/WWW/k-12/Numbers/Math/Mathematical_Thinking
...
0

Que dis-tu de ça:

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
pajics
la source
0

Essaye ça

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'
user1194101
la source
0

Essayez cette 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
snoopy
la source
0

Cela gérera correctement les problèmes avec l'anniversaire et l'arrondissement:

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

SELECT DATEDIFF(YEAR, '0:0', getdate()-@dob)
Digi314
la source
2
Ne gère pas correctement les années bissextiles SELECT DATEDIFF (YEAR, '0: 0', convert (datetime, '2014-02-28') -'2012-02-29 ') donne 2, mais ne devrait être que 1
Peter Kerr
0

La solution d'Ed Harper est la plus simple que j'ai trouvée et ne renvoie jamais la mauvaise réponse lorsque le mois et le jour des deux dates sont distants d'un jour ou moins. J'ai fait une légère modification pour gérer les âges négatifs.

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
clovis517
la source
0

La réponse marquée comme correcte est plus proche de l'exactitude, mais elle échoue dans le scénario suivant - où l' année de naissance est l'année bissextile et le jour après le mois de février

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

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


OU

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

- La solution suivante me donne des résultats plus précis.

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

Cela a fonctionné dans presque tous les scénarios, en considérant l'année bissextile, la date du 29 février, etc.

Veuillez me corriger si cette formule présente une lacune.

Bhushan Borole
la source
La formule finale est presque exacte comme dans cette réponse stackoverflow.com/a/1572235/168747 . Mais celui-ci est moins lisible et contient des éléments inutiles floor.
Marek
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
Alfredo Papirriqui
la source
0

Voici comment je calcule l'âge en fonction d'une date de naissance et d'une date actuelle.

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
Komengem
la source
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
Vova
la source
-1: sera faux à tout moment month(compare) > month(dob)MAIS day(compare) < day(dob), par exemple select dbo.AgeAtDate('2000-01-14', '2016-02-12').
JonBrave
Vous avez raison, merci pour cette affaire, ont mis à jour la fonction
Vova
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
Masum
la source
0

Qu'en est-il d'une solution avec uniquement des fonctions de date, pas de mathématiques, pas de soucis pour l'année bissextile

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
fcaserio
la source
0

Après avoir essayé BEAUCOUP de méthodes, cela fonctionne 100% du temps en utilisant la fonction MS SQL FORMAT moderne au lieu de convertir en style 112. Les deux fonctionneraient mais c'est le moins de code.

Quelqu'un peut-il trouver une combinaison de dates qui ne fonctionne pas? Je ne pense pas qu'il y en ait un :)

--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
ukgav
la source
-2

Nous avons utilisé quelque chose comme ici, mais en prenant ensuite l'âge moyen:

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

Remarquez, le ROND est à l'extérieur plutôt qu'à l'intérieur. Cela permettra à l'AVG d'être plus précis et nous n'ARRONDONS qu'une seule fois. Le rendre plus rapide aussi.

PCPGMR
la source
-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 
Diego Sapigna
la source
-2
SELECT CAST(DATEDIFF(dy, @DOB, GETDATE()+1)/365.25 AS int)
Alex
la source
Je vois des votes à la baisse, mais je ne vois pas d'exemples qui prouvent que c'est cassé.
Alex