取月末日期
月度对账、账单周期、月末快照这类需求都需要「这个月的最后一天」。月份长度不固定,二月还会遇到闰年,所以不能按三十或三十一号写死,必须由日期运算推出来。MySQL 提供了专用函数,PostgreSQL 没有同名函数,需要用月初截断加一个月的区间再减一天来算。两种写法都要留意返回值的类型:PG 的日期运算结果通常是带时间的类型,与日期列比较前要做转换。
基本信息
| 适用平台 | MySQL 8.0 / PostgreSQL 12 及以上 |
|---|---|
| MySQL 函数 | 专用函数直接返回当月最后一天,忽略时分秒 |
| PostgreSQL 写法 | 月初截断后加一个月再减一天 |
| 返回类型 | PostgreSQL 运算结果为带时间类型,比较前需转换 |
| 典型用途 | 月结区间、订阅到期日、报表期末余额 |
典型使用场景
- 月度对账:按自然月切分数据区间
- 订阅到期:按月末统一续费或结算
- 报表期末快照:取每月最后一天的数据作为结存
- 账单周期生成:下月月末作为本周期结束日
- 补全日历维度:给每个月份补上结束日期
两库写法
两库写法
-- MySQL:函数直接返回当月最后一天
SELECT LAST_DAY('2024-02-15'); -- 结果是 2024-02-29
SELECT LAST_DAY(CURDATE());
SELECT LAST_DAY(DATE_ADD(CURDATE(), INTERVAL 1 MONTH)); -- 下月月末
-- PostgreSQL:月初截断,加一个月再减一天
SELECT (date_trunc('month', DATE '2024-02-15') + INTERVAL '1 month - 1 day')::date;
-- 结果是 2024-02-29
-- PostgreSQL:比较日期列前记得转成日期类型
-- SELECT * FROM bills
-- WHERE bill_date <= (date_trunc('month', now()) + INTERVAL '1 month - 1 day')::date;
-- 月初日期同样是常用口径:直接截断到月
SELECT date_trunc('month', now())::date AS month_start;口径对照
| 需求 | MySQL 写法 | PostgreSQL 写法 |
|---|---|---|
| 当月最后一天 | 专用函数 | 月初截断加一个月减一天 |
| 下月最后一天 | 对当前日期加一个月后再取月末 | 同样先加一个月再截断计算 |
| 月初日期 | 用日期格式化截断到月 | 截断函数直接得到月初 |
| 返回类型 | 日期类型 | 带时间类型,建议转换 |
| 闰年二月 | 自动处理 | 自动处理 |
把月末当成固定三十或三十一号是最常见的错误,二月与闰年会让数字直接错位。任何与账单、结算相关的月末口径都应通过日期运算推导。
月末当天有时分秒的记录如果被包含进来,区间口径就变成了「到月末最后一刻」。用日期列直接比较,或者在区间边界上用「小于下月月初」的写法能避免这种含糊。