SQLite: How to calculate age from birth date

后端 未结 8 1807
独厮守ぢ
独厮守ぢ 2020-12-16 15:00

What is the best way to calculate the age in years from a birth date in sqlite3?

相关标签:
8条回答
  • 2020-12-16 15:14

    I have spent whole my Weekend on this Topic and created this Query.

    SELECT ID,
           Name,
           InitialDate,
           LastDate,
           CASE 
               WHEN strftime('%m', LastDate) > strftime('%m', InitialDate) THEN strftime('%Y', LastDate) - strftime('%Y', InitialDate) 
               WHEN strftime('%m', LastDate) < strftime('%m', InitialDate) THEN strftime('%Y', LastDate) - strftime('%Y', InitialDate) - 1 
               WHEN strftime('%m', LastDate) = strftime('%m', InitialDate) THEN 
               CASE 
                   WHEN strftime('%d', LastDate) >= strftime('%d', InitialDate) THEN strftime('%Y', LastDate) - strftime('%Y', InitialDate) 
                   ELSE strftime('%Y', LastDate) - strftime('%Y', InitialDate) - 1 
               END 
           END AS Years,
           CASE
               WHEN strftime('%m', LastDate) == strftime('%m', InitialDate) THEN
                   CASE
                       WHEN strftime('%d', LastDate) == strftime('%d', InitialDate)    THEN ( strftime('%m', LastDate) - strftime('%m', InitialDate) ) -- i.e., 0
                       WHEN strftime('%d', LastDate) > strftime('%d', InitialDate)     THEN ( strftime('%m', LastDate) - strftime('%m', InitialDate) ) -- i.e., 12
                       WHEN strftime('%d', InitialDate) > strftime('%d', LastDate)     THEN (strftime('%m', LastDate) - strftime('%m', InitialDate)) + 11 -- i.e., 11
                   END
               WHEN strftime('%m', LastDate) > strftime('%m', InitialDate) THEN 
                   CASE
                       WHEN strftime('%d', LastDate) == strftime('%d', InitialDate)    THEN strftime('%m', LastDate) - strftime('%m', InitialDate)
                       WHEN strftime('%d', LastDate) > strftime('%d', InitialDate)     THEN strftime('%m', LastDate) - strftime('%m', InitialDate)
                       WHEN strftime('%d', InitialDate) > strftime('%d', LastDate)     THEN ( strftime('%m', LastDate) - strftime('%m', InitialDate) ) - 1
                   END
               WHEN strftime('%m', InitialDate) > strftime('%m', LastDate) THEN
                   CASE 
                       WHEN strftime('%d', LastDate) == strftime('%d', InitialDate)    THEN 12 - ( strftime('%m', InitialDate) - strftime('%m', LastDate) )
                       WHEN strftime('%d', LastDate) > strftime('%d', InitialDate)     THEN 12 - ( strftime('%m', InitialDate) - strftime('%m', LastDate) )
                       WHEN strftime('%d', InitialDate) > strftime('%d', LastDate)     THEN 11 - (strftime('%m', InitialDate) - strftime('%m', LastDate))
                   END           
           END AS Months,
           CASE 
               WHEN strftime('%d', LastDate) == strftime('%d', InitialDate)    THEN 0
               WHEN strftime('%d', LastDate) > strftime('%d', InitialDate)     THEN strftime('%d', LastDate) - strftime('%d', InitialDate)
               WHEN strftime('%d', InitialDate) > strftime('%d', LastDate)     THEN ( strftime('%d', date(InitialDate, 'start of month', '+1 month', '-1 day') ) - strftime('%d', InitialDate) + strftime('%d', LastDate) )
                
       END AS Days
      FROM tbl_Dates;
    

    Tested on a Data Set consist of 248 Records. Years and Months are with calculated 100% Accuracy. While Days are 124 out of 248 Records are with Difference of ±1 Day(s). I would request other Genius Minds to Dig out and find the remaining solution. For me Its OK and working 100% Fine.

    0 讨论(0)
  • 2020-12-16 15:15

    I found this that maybe would help you:

    select
        case
            when date(dob, '+' ||
                strftime('%Y', 'now') - strftime('%Y', dob) ||
                ' years') >= date('now')
            then strftime('%Y', 'now') - strftime('%Y', dob)
            else strftime('%Y', 'now') - strftime('%Y', dob) - 1
        end
        as age
    from t;
    

    From http://www.mail-archive.com/sqlite-users@sqlite.org/msg20525.html

    0 讨论(0)
  • 2020-12-16 15:29
    SELECT (strftime('%Y', 'now') - strftime('%Y', Birth_Date)) - (strftime('%m-%d', 'now') < strftime('%m-%d', Birth_Date));
    

    This one works.
    I merely ported this MySQL example: http://dev.mysql.com/doc/refman/5.0/en/date-calculations.html

    0 讨论(0)
  • 2020-12-16 15:29

    Another solution is to use the day of the year %j as a fraction of the year by dividing it by 365.0. So you end up with:

    select strftime('%Y', 'now') + strftime('%j', 'now') / 365.2422) - (strftime('%Y', Birth_Date) + strftime('%j', Birth_Date) / 365.2422);
    

    You can then cast the result to an integer:

    select CAST(strftime('%Y', 'now') + strftime('%j', 'now') / 365.2422) - (strftime('%Y', Birth_Date) + strftime('%j', Birth_Date) / 365.2422) AS INT);
    

    or use ROUND() to round the outcome:

    select round(strftime('%Y', 'now') + strftime('%j', 'now') / 365.2422) - (strftime('%Y', Birth_Date) + strftime('%j', Birth_Date) / 365.2422));
    

    I have updated the calculation so it uses the correct decimal number of days in a solar year as noted by Robert in the comment below.

    The difference with the other calculations is that the result of this calculation is a decimal number that can be cast to an integer (to get the exact amount of years) or rounded (to get the approximate amount of years).

    For birthdays the approximate amount of years may not be that relevant, but for the age of something you bought it makes more sense.

    0 讨论(0)
  • 2020-12-16 15:32

    Just to clarify kai's answer (it seems that editing is now very much unwelcome, and comments have a strong size limitation and formatting issues):

    SELECT (strftime('%Y', 'now') - strftime('%Y', Birth_Date)) 
         - (strftime('%m-%d', 'now') < strftime('%m-%d', Birth_Date) );
    

    Let's assume we want full years: for the first calendar year of life, this would be zero.

    For the second calendar year, this would depend on the date -- i.e. it would be:

    • 1 for strftime('%m-%d', 'now') >= strftime('%m-%d', Birth_Date) ["case A"]
    • and 0 otherwise ["case B"] ;

    ( I assume sqlite does lexicographic comparison of two date strings and returns an integer value. )

    For any other calendar year, it would be the number of years between the current and the second -- i.e. strftime('%Y', 'now') - strftime('%Y', Birth_Date) - 1, plus the same as above.

    In other terms, we subtract 1 from strftime('%Y', 'now') - strftime('%Y', Birth_Date) only if the opposite of "case A" happens -- that is, if and only if strftime('%m-%d', 'now') < strftime('%m-%d', Birth_Date), hence the formula.

    0 讨论(0)
  • 2020-12-16 15:33

    To get @Bruno Costa's answer to work I had to add brackets around the strftime difference calculation on the 4th line and reverse the comparison to 'now' to be less than or equal: as I understand it the calculation is working out whether the calculated date is before or after today. If the calculated date is today or earlier then the birthday has already been this year or is today:

    select
        case
            when date(dob, '+' ||
                (strftime('%Y', 'now') - strftime('%Y', dob)) ||
                ' years') <= date('now')
            then strftime('%Y', 'now') - strftime('%Y', dob)
            else strftime('%Y', 'now') - strftime('%Y', dob) - 1
        end
        as age
    from t;
    

    Note that the solution linked to in @Bruno Costa's answer was untested.

    0 讨论(0)
提交回复
热议问题