last_day函数在mysql中用于返回指定日期所在月份的最后一天,支持date、datetime及合法字符串输入,返回date类型且时间部分归零;不可用于postgresql、sql server等非mysql环境,跨库需改用eomonth或日期运算逻辑。

LAST_DAY函数在MySQL中怎么用
LAST_DAY 是 MySQL 原生函数,输入一个日期(DATE、DATETIME 或能自动转为日期的字符串),返回该月最后一天的 DATE 值。它不支持 PostgreSQL、SQL Server 或 SQLite —— 这些数据库要么没这个函数,要么行为不同,直接照搬会报错。
常见错误现象:ERROR 1305 (42000): FUNCTION your_db.LAST_DAY does not exist,基本就是误用在非 MySQL 环境里了。
- 参数必须是合法日期值,
LAST_DAY('2024-02')可以(MySQL 自动补日),但LAST_DAY('2024-13')或LAST_DAY('abc')会返回NULL - 输入
DATETIME时,结果仍是DATE类型,时间部分被丢弃:LAST_DAY('2024-02-15 14:30:00')→'2024-02-29' - 对月末当天调用也安全:
LAST_DAY('2024-02-29')仍返回'2024-02-29'
如何用LAST_DAY计算“上个月末”
不能直接写 LAST_DAY(DATE_SUB(CURDATE(), INTERVAL 1 MONTH)) —— 这在 3 月 31 日执行时会出错:减一个月变成 2 月 31 日(非法日期),MySQL 可能转成 NULL 或静默修正为 3 月 3 日,导致 LAST_DAY 返回错误结果。
正确做法是先取“本月第一天”,再减一天,确保日期始终合法:
SELECT LAST_DAY(DATE_SUB(CURDATE(), INTERVAL DAYOFMONTH(CURDATE()) DAY));
更清晰的等价写法(推荐):
SELECT DATE_SUB(CURDATE(), INTERVAL DAYOFMONTH(CURDATE()) DAY);
这行本身已得到上月末,无需再套 LAST_DAY。硬要用 LAST_DAY 的话,稳妥路径是:
- 先算出“上个月的第一天”:
DATE_SUB(DATE_SUB(CURDATE(), INTERVAL DAYOFMONTH(CURDATE())-1 DAY), INTERVAL 1 MONTH) - 再对其用
LAST_DAY,即:LAST_DAY(DATE_SUB(DATE_SUB(CURDATE(), INTERVAL DAYOFMONTH(CURDATE())-1 DAY), INTERVAL 1 MONTH))
Oracle 和 PostgreSQL 用户别硬套LAST_DAY
Oracle 虽有同名函数,但参数要求更严格:只接受 DATE 类型,传入字符串必须显式 TO_DATE;而且它不接受 TIMESTAMP,会报 ORA-00932。
PostgreSQL 完全没有 LAST_DAY。常见替代是:
SELECT (DATE_TRUNC('month', CURRENT_DATE) + INTERVAL '1 month - 1 day')::DATE;
注意:这里用的是 DATE_TRUNC 而非 EXTRACT,后者无法直接构造日期;类型强制转换 ::DATE 不能省,否则结果是带时分秒的 TIMESTAMP。
SQL Server 用户请用 EOMONTH(),不是 LAST_DAY,也不是 DATEADD 手动算——EOMONTH 才是官方且处理闰年/大小月正确的函数。
为什么用LAST_DAY比手动拼日期更可靠
手动拼接如 CONCAT(YEAR(d), '-', LPAD(MONTH(d), 2, '0'), '-31') 看似简单,但会错判 4 月(30 天)、2 月(28/29)、甚至 2024 年 2 月 30 日这种不存在的日期,MySQL 插入时可能静默转成下月 2 日,查数据就对不上。
LAST_DAY 内部走的是日历逻辑,不是字符串操作:
- 自动识别大小月、平闰年
- 输入
'2023-01-15'、'2023-01'、'2023/01/15'都能正确返回'2023-01-31' - 和
DAYOFMONTH、MONTH等函数组合时,语义清晰,维护者一看就懂意图
真正容易被忽略的是环境适配——函数名一样不代表行为一致,连 MySQL 8.0 和 5.7 对非法输入的容忍度都略有差异,上线前务必在目标版本验证。











