MySQL的DATE_ADD函数必须按DATE_ADD(date, INTERVAL value unit)顺序传参,单位须单数大写;它自动处理日历逻辑如闰年跨月,但MONTH与DAY语义不同;WHERE中应避免对字段使用DATE_ADD以防索引失效。

DATE_ADD 用法和参数顺序别写反
MySQL 的 DATE_ADD 函数必须严格按 DATE_ADD(date, INTERVAL value unit) 顺序传参,很多人写成 DATE_ADD(INTERVAL ..., date) 直接报错 Incorrect parameter count。date 可以是日期字符串(如 '2024-01-01')、日期字段(如 created_at),或函数返回值(如 CURDATE())。
常见单位有:DAY、MONTH、YEAR、HOUR、MINUTE,注意单位名是单数且全大写,写 days 或 month 都会报错 Unknown or incorrect time value。
示例:给注册时间加 30 天作为试用到期日:
SELECT user_id, created_at, DATE_ADD(created_at, INTERVAL 30 DAY) AS expire_at FROM users;
跨月计算时 DATE_ADD 自动处理天数溢出
DATE_ADD 不是简单加数字,它理解日历逻辑。比如 DATE_ADD('2024-01-31', INTERVAL 1 MONTH) 结果是 '2024-02-29'(闰年),不是 '2024-02-31'(非法日期)。这点和直接用 + 运算符不同——'2024-01-31' + INTERVAL 1 MONTH 在某些旧版本 MySQL 中可能出错或截断。
但要注意:加月份不等于加固定天数。2024 年 1 月有 31 天,2 月只有 29 天,所以 DATE_ADD('2024-01-31', INTERVAL 1 MONTH) 和 DATE_ADD('2024-01-31', INTERVAL 31 DAY) 结果不同(后者是 2024-03-02)。
如果你需要“从今天起 30 个自然日”就用 DAY;如果需要“下个月同一天”,才用 MONTH。
在 WHERE 条件中用 DATE_ADD 判断是否过期
别写 WHERE expire_at 这种绕弯子写法。更清晰、可读性更好也更易索引的方式是把计算移到右边:
WHERE expire_at —— 已过期WHERE expire_at —— 7 天前已过期(<code>DATE_SUB等价于DATE_ADD(..., INTERVAL -7 DAY))-
WHERE expire_at BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 30 DAY)—— 未来 30 天内到期
注意:如果 expire_at 字段没建索引,或者用了函数包裹字段(如 WHERE DATE_ADD(expire_at, INTERVAL 1 DAY) > NOW()),会导致索引失效。
其他数据库的等价写法要换函数名
MySQL 用 DATE_ADD,PostgreSQL 用 date + interval '30 days',SQL Server 用 DATEADD(day, 30, date),SQLite 用 date(date, '+30 days')。语法差异不大,但函数名和参数顺序完全不同,迁移时容易漏改。
尤其注意 SQL Server 的 DATEADD 是 DATEADD(unit, value, date),unit 是第一个参数,且是单词(day 不带 s),而 MySQL 的 unit 是最后一个且带 s(DAY)。
跨数据库写法最稳妥的是用标准 SQL 的 date + INTERVAL '30' DAY(PostgreSQL 支持,MySQL 8.0+ 也支持,但旧版 MySQL 不认)。
DATE_ADD 本身不处理时区,得靠 CONVERT_TZ 或应用层对齐。

















