在MySQL中计算年龄(InnoDb)


69

如果我的出生日期以表格的形式存储在表格中,dd-mm-yyyy并且从当前日期中减去该日期,那么返回的日期格式是什么?

如何使用这种返回的格式来计算某人的年龄?


5
这是用于什么RDBMS?日期函数不是那么标准化的AFAIK。你是什​​么意思存储格式dd-mm-yyyy?如果它是date数据类型,则可能会以数字格式存储(例如,作为从某个起始点起带天数的整数)
Martin Smith

嗨,我将InnoDb与phpMyAdmin一起使用。...它存储为日期变量。我认为是yyyymmdd-上面犯了错误
user559142 2011年

如果将数据存储为DATE或DATETIME数据类型,则将其存储为二进制值,而不是以任何特定的人类可读格式存储。格式化仅在输出到文本时发生,并且取决于操作系统语言环境设置或您提供的显式格式说明等因素。尽可能使用期望DATE和DATETIME类型值的函数处理DATE和DATETIME值。这样您就不会在日期格式方面遇到任何问题。您可能仍然需要弄乱时区,但是至少您的计算结果会稍微偏离而不是完全中断。
gwideman 2014年

Answers:


62

如果该值存储为DATETIME数据类型:

SELECT YEAR(CURRENT_TIMESTAMP) - YEAR(dob) - (RIGHT(CURRENT_TIMESTAMP, 5) < RIGHT(dob, 5)) as age 
  FROM YOUR_TABLE

考虑leap年时不太精确:

SELECT DATEDIFF(CURRENT_DATE, STR_TO_DATE(t.birthday, '%d-%m-%Y'))/365 AS ageInYears
  FROM YOUR_TABLE t 

/365.25以处理leap年。但是在2000年,跳过了year年。但是如果您可以忍受1天的错误。
用户未知

38
还有就是MySQL官方文档中一个正确的答案:dev.mysql.com/doc/refman/5.0/en/date-calculations.html
mojuba

@mojuba:那是另一种方式,不一定正确-我认为如果操作不令人满意,OP不会将其标记为答案。如果您以此为理由撤消了我的投票,我将不胜感激,而且这个问题已经有两年了。
OMG小马

3
@OMG小马,很抱歉,但是假设一年中有365天不能给出正确的年龄计算。例如,对于一个40岁的人,您生日后10天内的年龄会不正确。
mojuba 2013年

1
@OMG小马不,不,不。公式中的错误大约为age / 4,因为这是公式中的of年数(这是未计入的额外天数)。尝试验证以下内容:timeanddate.com/date/duration.html
mojuba

246

您可以使用TIMESTAMPDIFF(unit, datetime_expr1, datetime_expr2)功能:

SELECT TIMESTAMPDIFF(YEAR, '1970-02-01', CURDATE()) AS age

演示版


12
小型,精确和轻松的解决方案。

4
这似乎是明显的赢家。我不知道为什么有人什么麻烦与复杂,混日子多发方法转换日期为字符串等
gwideman

3
最佳解决方案,但在本页面末尾很难找到。
Erik van de Ven

1
@ErikvandeVen以投票的顺序(不是最旧的)订购答案
Leandro

10
select *,year(curdate())-year(dob) - (right(curdate(),5) < right(dob,5)) as age from your_table

这样,您甚至可以考虑出生的月份和日期,以便更准确地计算年龄。


哇,效果很好-您能向我解释-(right(curdate(),5)<right(dob,5))部分的作用吗?
user559142 2011年

是。Right(...,5)从当前日期和出生日期提取mm-dd。您可以将它们与“ <”符号进行比较,如果出生日期和月份小于当前日期,则返回0,否则返回1。因此,您可以从年差中减去(0或1)。
Nicola Cossu 2011年

1
我会做一个大的修改。在我的MySQL右侧(dob,5),返回日期的小时-分钟部分。这可以通过使用来解决year(curdate())-year(dob) - (dayofyear(curdate()) < dayofyear(dob)) as age,我觉得dayofyear更优雅。
regilero 2013年

当然,如果dob恰好存储为日期时间,那么所有这些操作都会失败。只需使用TIMESTAMPDIFF()
gwideman 2014年


5
select floor(datediff (now(), birthday)/365) as age

对不起..修复它。他可以根据需要使用地板或天花板。
lobster1234 2011年

1
是的,如果那是OP想要的,它将无法达到那种精确度。但是,您需要有365个leap年才能使年龄相差1年,不是吗?
lobster1234 2011年

2

只是:

DATE_FORMAT(FROM_DAYS(TO_DAYS(NOW())-TO_DAYS(`birthDate`)), '%Y')+0 AS age

与TIMESTAMPDIFF()相比,这并不简单
gwideman 2014年

1

尝试这个:

SET @birthday = CAST('1980-05-01' AS DATE);
SET @today = CURRENT_DATE();

SELECT YEAR(@today) - YEAR(@birthday) - 
  (CASE WHEN
    MONTH(@birthday) > MONTH(@today) OR 
    (MONTH(@birthday) = MONTH(@today) AND DAY(@birthday) > DAY(@today)) 
      THEN 1 
      ELSE 0 
  END);

它返回今年-出生年份(该人今年生日后的年龄),并根据该人今年是否生日来进行调整。

它不会受到此处介绍的其他方法的舍入误差的影响。

这里自由改编


1

由于该问题已被标记mysql,因此我有以下适用于我的实现,希望其他RDBMS可以使用类似的替代方法。这是SQL:

select YEAR(now()) - YEAR(dob) - ( DAYOFYEAR(now()) < DAYOFYEAR(dob) ) as age 
from table 
where ...

1

简单地做

SELECT birthdate, (YEAR(CURDATE())-YEAR(birthdate)) AS age FROM `member` 

birthdate是保持生日日期名称通过YEAR()命令将CURDATE()转到年份的字段名称,减去生日日期字段中的YEAR()


1
如果不考虑采取月份和日期,数量可能有一年,与实际年龄的差异
胡安

0

这是在MySQL中计算年龄的方法:

select
  date_format(now(), '%Y') - date_format(date_of_birth, '%Y') - 
  (date_format(now(), '00-%m-%d') < date_format(date_of_birth, '00-%m-%d'))
as age from table

0

您可以创建一个函数来做到这一点:

drop function if exists getIdade;

delimiter |

create function getIdade( data_nascimento datetime )
returns int
begin
    declare idade int;
    declare ano_atual int;
    declare mes_atual int;
    declare dia_atual int;
    declare ano int;
    declare mes int;
    declare dia int;

    set ano_atual = year(curdate());
    set mes_atual = month( curdate());
    set dia_atual = day( curdate());

    set ano = year( data_nascimento );
    set mes = month( data_nascimento );
    set dia = day( data_nascimento );

    set idade = ano_atual - ano;

    if( mes > mes_atual ) then
            set idade = idade - 1;
    end if;

    if( mes = mes_atual and dia > dia_atual ) then
            set idade = idade - 1;
    end if;

    return idade;
end|

delimiter ;

现在,您可以从日期获取年龄:

select getIdade('1983-09-16');

如果日期格式为Ymd H:i:s,则可以执行以下操作:

select getIdade(substring_index('1983-09-16 23:43:01', ' ', 1));

您可以在任何地方重用此功能;)


2
如果您通过代码行付款(-),绝对可以。
gwideman 2014年

0

我更喜欢以这种方式使用函数。

DELIMITER $$ DROP FUNCTION IF EXISTS `db`.`F_AGE` $$
    CREATE FUNCTION `F_AGE`(in_dob datetime) RETURNS int(11)
        NO SQL
    BEGIN
       DECLARE l_age INT;
       IF DATE_FORMAT(NOW(  ),'00-%m-%d') >= DATE_FORMAT(in_dob,'00-%m-%d') THEN
          -- This person has had a birthday this year
          SET l_age=DATE_FORMAT(NOW(  ),'%Y')-DATE_FORMAT(in_dob,'%Y');
        ELSE
          -- Yet to have a birthday this year
          SET l_age=DATE_FORMAT(NOW(  ),'%Y')-DATE_FORMAT(in_dob,'%Y')-1;
       END IF;
       RETURN(l_age);
    END $$

    DELIMITER ;

现在使用

SELECT F_AGE('1979-02-11') AS AGE; 

要么

SELECT F_AGE(date) AS age FROM table;

0

有两种简单的方法可以做到这一点:

1-

select("users.birthdate",
            DB::raw("FLOOR(DATEDIFF(CURRENT_DATE, STR_TO_DATE(users.birthdate, '%Y-%m-%d'))/365) AS age_way_one"),

2

select("users.birthdate",DB::raw("(YEAR(CURDATE())-YEAR(users.birthdate)) AS age_way_two"))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.