Cómo calcular la edad (en años) según la fecha de nacimiento y getDate ()


172

Tengo una tabla que enumera a las personas junto con su fecha de nacimiento (actualmente un nvarchar (25))

¿Cómo puedo convertir eso en una fecha y luego calcular su edad en años?

Mis datos se ven de la siguiente manera

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

Me gustaría ver:

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

16
¿Por qué está almacenando valores de fecha como cadenas usando nvarchar (25) en lugar de usar la fecha nativa de la base de datos o el tipo de fecha y hora?
Jesper

La pregunta está etiquetada 2005 no 2008, por lo que el tipo nativo 'Fecha' no está disponible, pero definitivamente es una fecha y hora, y podría argumentarse SmallDateTime ya que no necesita la precisión.
Andrew

Hola, la razón para mantener las fechas como varchar es porque estoy importando esto desde un esquema de servidor que no es SQL, hubo algunos problemas al importarlos como datetime (y los otros formatos de fecha) y varchar se convirtió bien
Jimmy

77
@ James.Elsey, ¿tuvo problemas para importar y, como resultado, todas las fechas son válidas? nunca se puede estar seguro, a menos que use datetime o smalldatetime, con varchar, puede hacer que su importación funcione, pero tiene otros problemas más adelante. Además, nunca almacenaría la edad, cambia cada día, use una Vista
KM.

@KM Sí, hubo un problema al importar esos datos como una fecha, la única solución viable en ese momento era importarlos como nvarchars. Esta selección va a ser parte de un trabajo nocturno, por lo que almacenar la edad no debería ser un problema
Jimmy

Respuestas:


256

Hay problemas con los años bisiestos y el siguiente método, consulte la actualización a continuación:

prueba esto:

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

SALIDA:

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

(1 row(s) affected)

ACTUALIZACIÓN aquí hay algunos métodos más precisos:

MEJOR MÉTODO PARA AÑOS 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

puede cambiar lo anterior 10000a 10000.0y obtener decimales, pero no va a ser tan preciso como el método siguiente.

MEJOR MÉTODO PARA AÑOS EN 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

24
Esta tampoco es una solución exacta. Si tomo mi propio @dob como '1986-07-05 00:00:00' y ejecuto esto (uso otra variable en lugar de GETDATE()) en '2013-07-04 23:59:59' dice que Tengo 27 años, mientras que en ese momento todavía no. Código de ejemplo: 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
Esto no es exacto, ya que supone 8766 horas por año, lo que equivale a 365.25 días. Como no hay años con 365.25 días, esto será incorrecto cerca de la fecha de nacimiento de la persona con más frecuencia de lo que es correcto. Este método seguirá siendo más preciso.
Bacon Bits

1
Segundo comentario de @Bacon Bits: esto a menudo será incorrecto cuando la fecha actual esté cerca de la fecha de nacimiento de una persona.
flash

2
Creo que el primer bloque de texto hace que esta respuesta sea confusa. Si su método actualizado no tiene el problema con los años bisiestos, le sugiero (si realmente desea conservarlo) que lo baje al final de su respuesta.
ajbeaven

1
Si desea un cálculo EXACTO , DATEDIFF no lo hará @ShailendraMishra, porque se aproxima a días, etc. Por ejemplo, select datediff(year, '2000-01-05', '2018-01-04')devuelve 18, no 17 como debería. Utilicé el ejemplo anterior bajo el título "MEJOR MÉTODO PARA AÑOS EN INT" y funciona perfectamente. ¡Gracias!
openwonk

133

Tengo que lanzar este por ahí. Si convierte la fecha usando el estilo 112 (aaaammdd) a un número, puede usar un cálculo como este ...

(aaaaMMdd - aaaaMMdd) / 10000 = diferencia en años completos

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

salida

20091015    19800420    290595  29

14
Esto es casi mágico en cómo resuelve todos los problemas del año bisiesto. Vale la pena señalar que 112 es un número especial para la función CONVERTIR que formatea la fecha como aaaammdd. Posiblemente no sea obvio para todos cuando lo miras.
Derek Tomes

55
¡Eres un genio!
ercan

Mi equipo estaba teniendo un problema cuando la fecha que estábamos usando para encontrar la edad era el mismo día que la fecha con la que lo estamos comparando. Nos dimos cuenta de que cuando eran el mismo día (y si la edad iba a ser extraña) la edad se reduciría en uno. Esto funcionó perfectamente!
The Sheek Geek

1
Esta es la respuesta correcta: márquela como tal.
Snympi

44
El código más simple / más corto para este mismo método de cálculo en SQL Server 2012+ escode: 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

He usado esta consulta en nuestro código de producción durante casi 10 años:

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

66
No está mal, pero no es 100%, 2007/10/16 informará una edad de 2 años el
Andrew

44
Doh, nos estamos perdiendo lo obvio, es después del medio día, getdate devuelve un int, por lo que se redondeará, por supuesto. Copié pegué su respuesta y la ejecuté, por lo que automáticamente usé getdate, no el literal.
Andrew

2
Elegante y simple ¡Gracias!
William MB

9
Si hablamos de edades humanas, deberías calcularlo de la misma manera que los humanos calculan la edad. No tiene nada que ver con qué tan rápido se mueve la tierra y todo que ver con el calendario. Cada vez que transcurre el mismo mes y día que la fecha de nacimiento, incrementas la edad en 1. Esto significa que lo siguiente es lo más preciso porque refleja lo que los humanos quieren decir cuando dicen "edad":DATEDIFF(yy, @BirthDate, GETDATE()) - CASE WHEN (MONTH(@BirthDate) >= MONTH(GETDATE())) AND DAY(@BirthDate) > DAY(GETDATE()) THEN 1 ELSE 0 END
Bacon Bits

55
Lo siento, esa sintaxis está mal. CASE WHEN (MONTH(@date) > MONTH(GETDATE())) OR (MONTH(@date) = MONTH(GETDATE()) AND DAY(@date) > DAY(GETDATE())) THEN 1 ELSE 0 END
Bacon Bits

31

Muchas de las soluciones anteriores son incorrectas DateDiff (aa, @ Dob, @PassedDate) no considerará el mes y el día de ambas fechas. También tomar las partes del dardo y comparar solo funciona si se ordenan correctamente.

EL CÓDIGO SIGUIENTE FUNCIONA Y ES MUY SENCILLO:

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

¿Por qué multiplicas por 100? Esto funciona para mí ya que estoy tratando de replicar en la base de datos lo que existe en nuestra biblioteca de códigos, pero no pude explicar su función. Esta podría ser una pregunta estúpida :)
Jen

66
¡Gracias! Exactamente el código que esperaba aquí. ¡Este es el único código exactamente correcto en este hilo sin transformaciones de cadena (feas)! @Jen Toma el mes y el día del DoB (como el 25 de septiembre) y lo convierte en un valor entero 0925(o 925). Hace lo mismo con la fecha actual (como el 16 de diciembre 1216) y luego verifica si el valor entero DoB ya pasó. Para crear este número entero, el mes debe multiplicarse por 100.
bartlaarhoven

Gracias @bartlaarhoven :)
Jen

Solo mencionaré que si bien esto evita las transformaciones de cadenas, en su lugar hace mucho casting. Mi prueba muestra que no es significativamente más rápido que la respuesta de dotjoe , y el código es más detallado.
StriplingWarrior

la respuesta aceptada tiene una respuesta INT mucho más simple:(CONVERT(int,CONVERT(char(8),@Now,112))-CONVERT(char(8),@Dob,112))/10000
KM.

19

Debe considerar la forma en que se redondea el comando con fecha.

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>

Lo que adapté de aquí .

Tenga en cuenta que considerará el 28 de febrero como el cumpleaños de un salto por años no bisiestos, por ejemplo, una persona nacida el 29 de febrero de 2020 se considerará 1 año de edad el 28 de febrero de 2021 en lugar del 01 de marzo de 2021.


@Andrew - Corregido - Me perdí una de las sustituciones
Ed Harper

1
Versión simplificadaSELECT DATEDIFF(year, DOB, getdate()) + CASE WHEN (DATEADD(year,DATEDIFF(year, DOB, getdate()) , DOB) > getdate()) THEN - 1 ELSE 0 END)
Peter

Este es el enfoque correcto; No entiendo por qué los hacks son tan votados.
Salman A

8

EDITAR: ESTA RESPUESTA ES INCORRECTA. Lo dejo aquí como una advertencia a cualquiera que esté tentado a usar dayofyear, con una edición adicional al final.


Si, como yo, no desea dividir por días fraccionarios o arriesgarse a errores de redondeo / año bisiesto, aplaudo el comentario de @Bacon Bits en una publicación anterior https://stackoverflow.com/a/1572257/489865 donde dice:

Si hablamos de edades humanas, deberías calcularlo de la misma manera que los humanos calculan la edad. No tiene nada que ver con qué tan rápido se mueve la tierra y todo que ver con el calendario. Cada vez que transcurre el mismo mes y día que la fecha de nacimiento, aumenta la edad en 1. Esto significa que lo siguiente es lo más preciso porque refleja lo que los humanos quieren decir cuando dicen "edad".

Luego ofrece:

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

Aquí hay varias sugerencias que involucran comparar el mes y el día (y algunas se equivocan, ¡no permiten la ORcorrecta aquí!). Pero nadie ha ofrecido dayofyear, lo que parece tan simple y mucho más corto. Yo ofrezco:

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

[Nota: ¡En ninguna parte de SQL BOL / MSDN se DATEPART(dayofyear, ...)documenta realmente lo que devuelve! Entiendo que es un número en el rango 1-366; lo más importante, no cambia según la configuración regional según DATEPART(weekday, ...)& SET DATEFIRST.]


EDITAR: Por qué dayofyearsale mal : como ha comentado el usuario @AeroX, si la fecha de nacimiento / inicio es posterior a febrero en un año no bisiesto, la edad se incrementa un día antes cuando la fecha actual / final es un año bisiesto, por ejemplo '2015-05-26', '2016-05-25'da un 1 año de edad cuando aún debería ser 0. Comparar los dayofyearaños diferentes es claramente peligroso. Entonces usar MONTH()y DAY()es necesario después de todo.


Esto debería ser votado o incluso marcado como la respuesta. Es corto, elegante y lógicamente correcto.
z00l

1
Para todos los nacidos después de febrero, su edad se incrementa un día antes en cada año bisiesto utilizando el DayOfYearmétodo.
AeroX

44
@AeroX Gracias por detectar esta falla. Decidí dejar mi solución como una advertencia a cualquiera que pudiera o haya usado dayofyear, pero claramente editado para mostrar por qué sale mal. Espero que sea adecuado.
JonBrave

5

Como no hay una respuesta simple que siempre proporcione la edad correcta, esto es lo que se me ocurrió.

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 

Esto obtiene la diferencia de año entre la fecha de nacimiento y la fecha actual. Luego resta un año si la fecha de nacimiento aún no ha pasado.

Preciso todo el tiempo, independientemente de los años bisiestos o de la fecha de nacimiento.

Lo mejor de todo: sin función.


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

1
Desea getdate como el segundo argumento, no el primero, de lo contrario obtendrá resultados de números negativos y rondas de fecha, así que seleccione dateiff (aa, '20081231', getdate ()) informará una edad de 1, pero solo tendrían 10 meses. .
Andrew

1
Este cálculo da cálculos incorrectos para las personas que aún no han cumplido años este año.

3

Qué pasa:

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

¿No evitaría eso todos esos problemas de redondeo, truncamiento y desajuste?


Tu cálculo no es exacto. Por ejemplo: falla si toma '1986-07-05 00:00:00'para DOB y '2013-07-04 23:59:59'para la hora actual.
drinovc

@ub_coding ¿Ofrecen y responden o hacen otra pregunta?
Aaron C

esto: DECLARE @DOB datetime SET @ DOB = '19760229' SELECT Datepart (yy, convert (datetime, '19770228') - @ DOB) -1900 = 1 el problema principal es el intervalo de fev 29 para la mayoría de las soluciones, eso explica el redondeo truncado, etc. .
Leonardo Marques de Souza

3

Creo que esto es similar a otros publicados aquí ... pero esta solución funcionó para los ejemplos del año bisiesto 29/02/1976 al 01/03/2011 y también funcionó para el caso durante el primer año ... como 07/04 / 2011 al 07/03/2012 que el último publicado sobre la solución de año bisiesto no funcionó para ese caso de uso del primer año.

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

Encontrado aquí .


3

Simplemente verifique si la respuesta a continuación es factible.

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
)

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


Una forma más corta de hacer esto en SQL Server 2012+ es la siguiente, y evita las conversiones a 112 y el piso no es necesario:code: SELECT [Age] = (0+ FORMAT(@ToDate,'yyyyMMdd') - FORMAT(@DOB,'yyyyMMdd') ) /10000
ukgav

2

He pensado y buscado mucho sobre esto y tengo 3 soluciones que

  • calcular la edad correctamente
  • son cortos (en su mayoría)
  • son (en su mayoría) muy comprensibles.

Aquí hay valores de prueba:

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

Solución 1: Encontré este enfoque en una biblioteca js. Es mi favorito.

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

En realidad, agrega diferencia en años a DOB y si es mayor que la fecha actual, resta un año. Simple derecho? Lo único es que la diferencia en años se duplica aquí.

Pero si no necesita usarlo en línea, puede escribirlo así:

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

Solución 2: esta copiaba originalmente de @ bacon-bits. Es el más fácil de entender pero un poco largo.

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

Básicamente es calcular la edad como lo hacemos los humanos.


Solución 3: Mi amigo lo refactorizó en esto:

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

Este es el más corto pero es más difícil de entender. 50es solo un peso, por lo que la diferencia de días solo es importante cuando los meses son iguales. SIGNLa función es para transformar cualquier valor que obtenga en -1, 0 o 1. CEILING(0.5 *Es el mismo Math.max(0, value)pero no existe tal cosa en 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

Hay muchas respuestas 365.25 aquí. Recuerde cómo se definen los años bisiestos:

  • Cada cuatro años
    • excepto cada 100 años
      • excepto cada 400 años

Excelente respuesta Para aquellos que tienen curiosidad aquí, hay una explicación de por qué 365.2425 es el valor correcto para usar: grc.nasa.gov/WWW/k-12/Numbers/Math/Mathematical_Thinking/…
vvvv4d

0

Qué tal esto:

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

Prueba esto

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

Prueba esta solución:

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

Esto manejará correctamente los problemas con el cumpleaños y el redondeo:

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

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

2
No maneja los años bisiestos correctamente SELECCIONAR DATEDIFF (AÑO, '0: 0', convertir (fecha y hora, '2014-02-28') -'2012-02-29 ') da 2, pero solo debería ser 1
Peter Kerr

0

La solución de Ed Harper es la más simple que he encontrado y nunca devuelve la respuesta incorrecta cuando el mes y el día de las dos fechas están separados por 1 o menos días. Hice una ligera modificación para manejar edades negativas.

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

La respuesta marcada como correcta es más cercana a la precisión, pero falla en el siguiente escenario: donde el año de nacimiento es año bisiesto y el día es posterior al mes de febrero

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

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


O

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

- La siguiente solución me está dando resultados más precisos.

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

Funcionó en casi todos los escenarios, considerando el año bisiesto, la fecha como 29 de febrero, etc.

Corríjame si esta fórmula tiene alguna laguna.


La fórmula final es casi exacta como en esta respuesta stackoverflow.com/a/1572235/168747 . Pero el que está aquí es menos legible y contiene innecesario 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

0

Así es como calculo la edad dada una fecha de nacimiento y la fecha actual.

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: Se equivocará en cualquier momento month(compare) > month(dob)PERO day(compare) < day(dob), por ejemplo select dbo.AgeAtDate('2000-01-14', '2016-02-12').
JonBrave

Tienes razón, gracias por este caso, han actualizado la función
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

0

¿Qué pasa con una solución con solo funciones de fecha, no matemáticas, no te preocupes por el año bisiesto?

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

Después de probar MUCHOS métodos, esto funciona el 100% del tiempo usando la moderna función MS SQL FORMAT en lugar de convertir al estilo 112. Cualquiera funcionaría pero este es el código mínimo.

¿Alguien puede encontrar una combinación de fecha que no funciona? No creo que haya uno :)

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

Usamos algo como aquí, pero luego tomamos la edad promedio:

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

Observe que la RONDA está afuera más que adentro. Esto permitirá que el AVG sea más preciso y RODEEMOS solo una vez. Haciéndolo más rápido también.


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

Veo votos negativos pero no veo ejemplos que prueben que esto está roto.
Alex
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.