eomonth是sql server 2012+内置日期函数,直接返回指定日期所在月最后一天(如eomonth(getdate())得2026-10-31),支持可选月偏移量,输入null返回null,自动处理闰年、大小月及跨年。

SQL Server里EOMONTH函数的基本用法
EOMONTH 是 SQL Server 2012 及以上版本才支持的日期函数,用来直接算出指定日期所在月份的最后一天。它比手动拼 DATEADD + DAY 组合更简洁、可读性更强,也避免了跨年、闰年等边界问题。
最常用形式是 EOMONTH(@date),返回 @date 所在月的最后一天(date 类型,不带时间部分);也可以加第二个参数偏移月数,比如 EOMONTH(@date, 1) 返回下个月末。
注意:如果输入是 NULL,结果也是 NULL,不会报错——这点在 JOIN 或 WHERE 条件中容易被忽略,导致逻辑漏数据。
为什么EOMONTH(@date, 0)和直接写@date有时结果不同
关键在于输入值是否含时间部分。EOMONTH 总是返回当月最后一天的 00:00:00(date 类型),而如果你传入的是 datetime 或 datetime2 值(比如 '2024-03-15 14:30:00'),它仍只看日期部分(即 '2024-03-15'),结果是 '2024-03-31',不是 '2024-03-15'。
- 传入
'2024-02-10'→ 返回'2024-02-29'(自动适配闰年) - 传入
'2024-02-10 23:59:59.999'→ 仍是'2024-02-29',时间部分被忽略 - 传入
NULL→ 返回NULL,不是当前月末
在WHERE条件中用EOMONTH筛选“当月所有记录”要小心
常见错误是写成 WHERE order_date ,这会把历史所有订单都查出来。真正需要的是“订单日期落在本月内”,得配合月初一起用:
正确写法是:WHERE order_date >= DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1) AND order_date
更稳妥的做法是用 YEAR(order_date) = YEAR(GETDATE()) AND MONTH(order_date) = MONTH(GETDATE()),虽然性能略差,但语义清晰、索引友好,且不受时区或 GETDATE() 调用时机影响。
如果表数据量大,又必须用 EOMONTH 做范围查询,记得给 order_date 字段建索引,并确认执行计划是否走了索引 Seek。
兼容老版本SQL Server(2008及以前)的替代方案
如果数据库版本低于 2012,EOMONTH 不可用,得手动构造月末日期。最可靠的方式是:先算下个月第一天,再减一天:
DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEFROMPARTS(YEAR(@date), MONTH(@date), 1)))
注意:不能简单用 DATEADD(MONTH, 1, @date) - 1,因为 @date 含时间部分时,减 1 天可能得到 23:59:59.997 这类值,类型隐式转换可能引发意外截断或比较失败。
另外,DATEFROMPARTS 也是 2012+ 才有,2008 R2 及更早需改用 DATEADD(MONTH, DATEDIFF(MONTH, 0, @date), 0) 得到当月第一天,再套一层 DATEADD 算月末。
跨版本迁移时,最容易被忽略的是函数可用性检查和 NULL 输入行为差异——别假设所有环境都支持同一个语法。










