mysql用timestampdiff(year, birth_date, curdate())计算周岁,按日历逻辑校准生日;postgresql用extract(year from age(current_date, birth_date))::int;sql server需用datediff加case判断生日是否已过。

用 TIMESTAMPDIFF 直接算周岁(MySQL)
MySQL 里最可靠的方式是用 TIMESTAMPDIFF(YEAR, birth_date, CURDATE()),它按日历逻辑计算整年差:只看年份差,但会自动校准是否已过生日。比如 birth_date = '2000-05-15',今天是 '2024-04-20',结果是 23;到 '2024-05-15' 才变成 24。
注意别用 YEAR(CURDATE()) - YEAR(birth_date)——它只减年份数字,无视月份日期,会导致未过生日时就多算一岁。
-
TIMESTAMPDIFF第一个参数必须是YEAR,不能写成year(大小写敏感) - 第二个参数是出生日期字段,必须是
DATE或DATETIME类型,CHAR或VARCHAR存的日期字符串要先用STR_TO_DATE()转换 - 如果
birth_date为NULL,结果也是NULL,需要加IFNULL(..., 0)或COALESCE(..., 0)处理
PostgreSQL 怎么算周岁
PostgreSQL 没有内置的“周岁”函数,得靠日期运算推导:EXTRACT(YEAR FROM AGE(CURRENT_DATE, birth_date))::INT。其中 AGE() 返回一个 interval,EXTRACT(YEAR FROM ...) 取出整年部分,刚好等价于周岁。
别用 EXTRACT(YEAR FROM CURRENT_DATE) - EXTRACT(YEAR FROM birth_date)——同样会错判未过生日的情况。
-
AGE()的参数顺序是AGE(终点, 起点),反了会得到负数 - 如果
birth_date是NULL,AGE()返回NULL,整个表达式也返回NULL - 该写法在 PostgreSQL 9.0+ 全版本兼容,无需额外扩展
SQL Server 中避免用 DATEDIFF(YEAR, ...)
DATEDIFF(YEAR, birth_date, GETDATE()) 是常见误区:它只比较年份和月份数字,不看具体日期。例如 birth_date = '2000-12-31',哪怕今天是 '2024-01-01',也会返回 24(实际才满 23 周岁)。
正确做法是用条件判断:DATEDIFF(YEAR, birth_date, GETDATE()) - CASE WHEN DATEADD(YEAR, DATEDIFF(YEAR, birth_date, GETDATE()), birth_date) > GETDATE() THEN 1 ELSE 0 END。本质是先算年份差,再检查“今年生日是否已过”,没过就减 1。
- 这个表达式在 SQL Server 2008+ 可直接用,无需 CLR 或函数封装
- 如果表数据量大,这个计算无法走索引,建议把年龄作为计算列(
AS ... PERSISTED)或应用层缓存 - 注意
GETDATE()是本地时区,如需 UTC 时间,改用GETUTCDATE()并确保birth_date也是 UTC
跨数据库可移植的简化方案(精度可接受时)
如果业务允许 ±1 天误差(比如仅用于分组统计、年龄段筛选),可用通用写法:FLOOR(DATEDIFF(CURDATE(), birth_date) / 365.25)(MySQL)或 FLOOR(EXTRACT(EPOCH FROM (CURRENT_DATE - birth_date)) / (365.25 * 86400))(PostgreSQL)。它基于平均年长估算,不依赖生日是否已过。
这种写法适合报表类查询或 ETL 预处理,但绝不能用于法律、医疗、入学等对周岁定义严格的场景。
- 365.25 是格里高利历平均年长,比用 365 更准,但仍会因闰年分布产生微小偏差
- 所有数据库都支持基础日期相减,但语法细节不同:MySQL 返回天数,PostgreSQL 返回
interval,SQL Server 需用DATEDIFF(day, ...) - 一旦用了浮点除法,结果类型变为
FLOAT或DOUBLE,务必套FLOOR()或CAST(... AS INT)截断小数
实际用的时候,优先选各数据库原生的语义化函数(TIMESTAMPDIFF、AGE),而不是自己拼逻辑——边界情况太多,比如 2 月 29 日出生的人,不同数据库处理方式还不一致。










