How to calculate age in T-SQL with years, months, and days

后端 未结 24 1544
无人共我
无人共我 2020-11-22 05:42

What would be the best way to calculate someone\'s age in years, months, and days in T-SQL (SQL Server 2000)?

The datediff function doesn\'t handle year

相关标签:
24条回答
  • I use this Function I modified (the Days part) From @Dane answer: https://stackoverflow.com/a/57720/2097023

    CREATE FUNCTION dbo.EdadAMD
        (
            @FECHA DATETIME
        )
        RETURNS NVARCHAR(10)
        AS
        BEGIN
            DECLARE
                @tmpdate DATETIME
              , @years   INT
              , @months  INT
              , @days    INT
              , @EdadAMD NVARCHAR(10);
    
            SELECT @tmpdate = @FECHA;
    
            SELECT @years = DATEDIFF(yy, @tmpdate, GETDATE()) - CASE
                                              WHEN (MONTH(@FECHA) >    MONTH(GETDATE()))
                                                 OR (
                                                    MONTH(@FECHA) = MONTH(GETDATE())
                                              AND DAY(@FECHA) > DAY(GETDATE())
                                              ) THEN
                                                    1
                                                ELSE
                                                    0
                                        END;
        SELECT @tmpdate = DATEADD(yy, @years, @tmpdate);
        SELECT @months = DATEDIFF(m, @tmpdate, GETDATE()) - CASE
                                  WHEN DAY(@FECHA) > DAY(GETDATE()) THEN
                                                                1
                                                            ELSE
                                                                0
                                                        END;
        SELECT @tmpdate = DATEADD(m, @months, @tmpdate);
    
        IF MONTH(@FECHA) = MONTH(GETDATE())
           AND DAY(@FECHA) > DAY(GETDATE())
              SELECT @days = 
                DAY(EOMONTH(GETDATE(), -1)) - (DAY(@FECHA) - DAY(GETDATE()));
        ELSE
            SELECT @days = DATEDIFF(d, @tmpdate, GETDATE());
    
        SELECT @EdadAMD = CONCAT(@years, 'a', @months, 'm', @days, 'd');
    
        RETURN @EdadAMD;
    
    END; 
    GO
    

    It works pretty well.

    0 讨论(0)
  • 2020-11-22 06:17

    I've seen the question several times with results outputting Years, Month, Days but never a numeric / decimal result. (At least not one that doesn't round incorrectly). I welcome feedback on this function. Might not still need a little adjusting.

    -- Input to the function is two dates. -- Output is the numeric number of years between the two dates in Decimal(7,4) format. -- Output is always always a possitive number.

    -- NOTE:Output does not handle if difference is greater than 999.9999

    -- Logic is based on three steps. -- 1) Is the difference less than 1 year (0.5000, 0.3333, 0.6667, ect.) -- 2) Is the difference exactly a whole number of years (1,2,3, ect.)

    -- 3) (Else)...The difference is years and some number of days. (1.5000, 2.3333, 7.6667, ect.)



    CREATE Function [dbo].[F_Get_Actual_Age](@pi_date1 datetime,@pi_date2 datetime)
    RETURNS Numeric(7,4)
    AS
    BEGIN
    
    Declare 
     @l_tmp_date    DATETIME
    ,@l_days1       DECIMAL(9,6)
    ,@l_days2       DECIMAL(9,6)
    ,@l_result      DECIMAL(10,6)
    ,@l_years       DECIMAL(7,4)
    
    
      --Check to make sure there is a date for both inputs
      IF @pi_date1 IS NOT NULL and @pi_date2 IS NOT NULL  
      BEGIN
    
        IF @pi_date1 > @pi_date2 --Make sure the "older" date is in @pi_date1
          BEGIN
            SET @l_tmp_date = @pi_date2
            SET @pi_date2 = @Pi_date1
            SET @pi_date1 = @l_tmp_date
          END
    
        --Check #1 If date1 + 1 year is greater than date2, difference must be less than 1 year
        IF DATEADD(YYYY,1,@pi_date1) > @pi_date2  
          BEGIN
              --How many days between the two dates (numerator)
            SET @l_days1 = DATEDIFF(dd,@pi_date1, @pi_date2) 
              --subtract 1 year from date2 and calculate days bewteen it and date2
              --This is to get the denominator and accounts for leap year (365 or 366 days)
            SET @l_days2 = DATEDIFF(dd,dateadd(yyyy,-1,@pi_date2),@pi_date2) 
            SET @l_years = @l_days1 / @l_days2 -- Do the math
          END
        ELSE
          --Check #2  Are the dates an exact number of years apart.
          --Calculate years bewteen date1 and date2, then add the years to date1, compare dates to see if exactly the same.
          IF DATEADD(YYYY,DATEDIFF(YYYY,@pi_date1,@pi_date2),@pi_date1) = @pi_date2  
            SET @l_years = DATEDIFF(YYYY,@pi_date1, @pi_date2) --AS Years, 'Exactly even Years' AS Msg
          ELSE
          BEGIN
            --Check #3 The rest of the cases.
            --Check if datediff, returning years, over or under states the years difference
            SET @l_years = DATEDIFF(YYYY,@pi_date1, @pi_date2)
            IF DATEADD(YYYY,@l_years,@pi_date1) > @pi_date2
              SET @l_years = @l_years -1
              --use basicly same logic as in check #1  
            SET @l_days1 = DATEDIFF(dd,DATEADD(YYYY,@l_years,@pi_date1), @pi_date2) 
            SET @l_days2 = DATEDIFF(dd,dateadd(yyyy,-1,@pi_date2),@pi_date2) 
            SET @l_years = @l_years + @l_days1 / @l_days2
            --SELECT @l_years AS Years, 'Years Plus' AS Msg
          END
      END
      ELSE
        SET @l_years = 0  --If either date was null
    
    RETURN @l_Years  --Return the result as decimal(7,4)
    END  
    

    `

    0 讨论(0)
  • 2020-11-22 06:19

    For the ones that want to create a calculated column in a table to store the age:

    CASE WHEN DateOfBirth< DATEADD(YEAR, (DATEPART(YEAR, GETDATE()) - DATEPART(YEAR, DateOfBirth))*-1, GETDATE()) 
         THEN DATEPART(YEAR, GETDATE()) - DATEPART(YEAR, DateOfBirth)
         ELSE DATEPART(YEAR, GETDATE()) - DATEPART(YEAR, DateOfBirth) -1 END
    
    0 讨论(0)
  • 2020-11-22 06:20

    Are you trying to calculate the total days/months/years of an age? do you have a starting date? Or are you trying to dissect it (ex: 24 years, 1 month, 29 days)?

    If you have a start date that you're working with, datediff will output the total days/months/years with the following commands:

    Select DateDiff(d,'1984-07-12','2008-09-11')
    
    Select DateDiff(m,'1984-07-12','2008-09-11')
    
    Select DateDiff(yyyy,'1984-07-12','2008-09-11')
    

    with the respective outputs being (8827/290/24).

    Now, if you wanted to do the dissection method, you'd have to subtract the number of years in days (days - 365*years), and then do further math on that to get the months, etc.

    0 讨论(0)
  • 2020-11-22 06:21

    Implemented by arithmetic with ISO formatted date.

    declare @now date,@dob date, @now_i int,@dob_i int, @days_in_birth_month int
    declare @years int, @months int, @days int
    set @now = '2013-02-28' 
    set @dob = '2012-02-29' -- Date of Birth
    
    set @now_i = convert(varchar(8),@now,112) -- iso formatted: 20130228
    set @dob_i = convert(varchar(8),@dob,112) -- iso formatted: 20120229
    set @years = ( @now_i - @dob_i)/10000
    -- (20130228 - 20120229)/10000 = 0 years
    
    set @months =(1200 + (month(@now)- month(@dob))*100 + day(@now) - day(@dob))/100 %12
    -- (1200 + 0228 - 0229)/100 % 12 = 11 months
    
    set @days_in_birth_month = day(dateadd(d,-1,left(convert(varchar(8),dateadd(m,1,@dob),112),6)+'01'))
    set @days = (sign(day(@now) - day(@dob))+1)/2 * (day(@now) - day(@dob))
              + (sign(day(@dob) - day(@now))+1)/2 * (@days_in_birth_month - day(@dob) + day(@now))
    -- ( (-1+1)/2*(28 - 29) + (1+1)/2*(29 - 29 + 28))
    -- Explain: if the days of now is bigger than the days of birth, then diff the two days
    --          else add the days of now and the distance from the date of birth to the end of the birth month 
    select @years,@months,@days -- 0, 11, 28 
    

    Test Cases

    The approach of days is different from the accepted answer, the differences shown in the comments below:

           dob        now  years  months  days 
    2012-02-29 2013-02-28      0      11    28  --Days will be 30 if calculated by the approach in accepted answer. 
    2012-02-29 2016-02-28      3      11    28  --Days will be 31 if calculated by the approach in accepted answer, since the day of birth will be changed to 28 from 29 after dateadd by years. 
    2012-02-29 2016-03-31      4       1     2
    2012-01-30 2016-02-29      4       0    30
    2012-01-30 2016-03-01      4       1     2  --Days will be 1 if calculated by the approach in accepted answer, since the day of birth will be changed to 30 from 29 after dateadd by years.
    2011-12-30 2016-02-29      4       1    30
    

    An short version of Days by case statement:

    set @days = CASE WHEN day(@now) >= day(@dob) THEN day(@now) - day(@dob)
                     ELSE @days_in_birth_month - day(@dob) + day(@now) END
    

    If you want the age of years and months only, it could be simpler

    set @years = ( @now_i/100 - @dob_i/100)/100
    set @months =(12 + month(@now) - month(@dob))%12 
    select @years,@months -- 1, 0
    

    NOTE: A very useful link of SQL Server Date Formats

    0 讨论(0)
  • 2020-11-22 06:23

    DateTime values in T-SQL are stored as floats. You can just subtract the dates from each other and you now have a new date that is the timespan between them.

    declare @birthdate datetime
    set @birthdate = '6/15/1974'
    
    --age in years - short version
    print year(getdate() - @birthdate) - year(0)
    
    --age in years - visualization
    declare @mindate datetime
    declare @span datetime
    
    set @mindate = 0
    set @span = getdate() - @birthdate
    
    print @mindate
    print @birthdate
    print getdate()
    print @span
    --substract minyear from spanyear to get age in years
    print year(@span) - year(@mindate)
    print month(@span)
    print day(@span)
    
    0 讨论(0)
提交回复
热议问题