date_add正确用法是date_add(日期, interval 数值 单位),单位须大写;月末加月需先归零再计算;where中应避免对字段使用date_add以防索引失效。

DATE_ADD 用法和参数顺序别写反
DATE_ADD 的第一个参数是日期,第二个是间隔表达式,不是反过来。很多人写成 DATE_ADD('1 day', '2023-01-01'),结果报错或返回 NULL —— MySQL 不认这种顺序。
正确写法是:DATE_ADD('2023-01-01', INTERVAL 1 DAY)。注意 INTERVAL 是关键字,不能省;单位如 DAY、MONTH、YEAR 必须大写(虽然小写在某些模式下也能过,但不保险)。
- 日期参数可以是
DATE、DATETIME或字符串,比如'2023-01-01'、'2023-01-01 12:00:00' - 如果传入非法日期(如
'2023-02-30'),函数直接返回NULL,不会自动修正 - 负数偏移用
-1,不是NEGATIVE 1:写INTERVAL -1 MONTH,不是INTERVAL NEGATIVE 1 MONTH
用 DATE_ADD 做月末/月初计算容易掉坑
想加一个月得到“下个月第一天”,别直接 DATE_ADD('2023-01-31', INTERVAL 1 MONTH) —— 结果是 2023-03-03,不是 2023-02-01。因为 MySQL 先加月再校验日期,1月31日 +1月 → 2月31日 → 自动进位到3月3日。
真要算“下月1号”,得组合用:DATE_ADD(DATE_SUB('2023-01-31', INTERVAL DAYOFMONTH('2023-01-31')-1 DAY), INTERVAL 1 MONTH),也就是先归零到当月1号,再加月。
- 更稳妥的做法是用
LAST_DAY()配合DATE_ADD:比如“本月最后一天” =LAST_DAY('2023-01-15'),“下月最后一天” =LAST_DAY(DATE_ADD('2023-01-15', INTERVAL 1 MONTH)) -
DAYOFMONTH()返回的是数值,不是字符串,别加引号 - 跨年时(如 2023-12-15 +1 MONTH)没问题,MySQL 会自动处理年份进位
性能和索引友好性:别在 WHERE 里对字段用 DATE_ADD
写 WHERE DATE_ADD(create_time, INTERVAL 7 DAY) > NOW() 看似合理,但会让 create_time 字段上的索引完全失效 —— 因为 MySQL 无法把函数作用于索引列后做范围查找。
应该把函数挪到右边常量侧:WHERE create_time > DATE_SUB(NOW(), INTERVAL 7 DAY)。这样 create_time 可走索引,查询快得多。
- 同理,
DATE_ADD(col, INTERVAL 1 HOUR) = '2023-01-01 12:00:00'也建议改写为col = DATE_SUB('2023-01-01 12:00:00', INTERVAL 1 HOUR) - 如果业务必须频繁做带偏移的范围查询,考虑在表里冗余一个预计算字段(如
expire_at),并建索引 -
DATE_ADD本身计算开销极小,瓶颈永远在索引是否命中
和 DATE_SUB、+ 运算符的区别在哪
DATE_ADD(dt, INTERVAL -1 DAY) 和 DATE_SUB(dt, INTERVAL 1 DAY) 功能完全等价,选哪个纯看可读性。但别用 dt - INTERVAL 1 DAY 这种写法 —— 它在某些 MySQL 版本(尤其是 5.7 之前)行为不稳定,可能被解析成减法运算而非日期运算。
另外,DATETIME 列支持直接加减数字(如 dt + 1),但这其实是把时间转成秒级整数再加,极易出错。比如 '2023-01-01 00:00:00' + 1 = 20230101000001(拼接结果),不是加一秒。
- 坚持用
DATE_ADD/DATE_SUB,语义清晰、版本兼容性强 - 单位别混用:
INTERVAL 30 MINUTE不能写成INTERVAL 0.5 HOUR(MySQL 不支持小数单位) - 时区敏感操作(如加8小时)要确认服务器时区设置,
DATE_ADD本身不自动转换时区
事情说清了就结束。真正麻烦的不是语法,是那些看似能跑通、实则逻辑错位的边界场景——比如月末加月、索引失效、时区漂移。这些地方不测数据,光看文档很难发现。









