eomonth是sql server 2012+获取当月最后一天最轻量可靠的方式,支持月偏移、自动处理闰年,null输入返回null,不兼容2008及更早版本。

直接用 EOMONTH 就能拿到当月最后一天,不用拼日期或查日历表
SQL Server 2012 起内置的 EOMONTH 是最轻量、最可靠的方式。它接受一个日期参数,返回该月最后一天的日期值(date 或 datetime 类型),自动处理大小月、闰年,完全不用手动计算。
最常用写法就是传入当前日期:
SELECT EOMONTH(GETDATE()); -- 返回类似 '2024-06-30'
注意:如果传入的是 datetime(比如 GETDATE()),返回仍是 datetime,但时间部分固定为 00:00:00.000;若只需日期,可显式转换:CAST(EOMONTH(GETDATE()) AS date)。
EOMONTH 的第二个参数控制偏移月数,别漏掉它
很多人只记得第一个参数(起始日期),却忽略第二个可选参数——整数型的月偏移量。它让函数能灵活向前/向后跳转月份,比如获取下个月末、上个月末、甚至去年 12 月最后一天。
-
EOMONTH('2024-01-15', 0)→2024-01-31(当月) -
EOMONTH('2024-01-15', 1)→2024-02-29(下月,2024 是闰年) -
EOMONTH('2024-01-15', -3)→2023-10-31(往前推 3 个月)
这个参数支持变量和列,适合在 WHERE 条件中动态截取「截至上月末的数据」:
WHERE order_date <h3>遇到 <code>NULL</code> 输入时 <code>EOMONTH</code> 直接返回 <code>NULL</code>,不是错误</h3><p>这是容易被误判为“函数失效”的点:只要第一个参数是 <code>NULL</code>,不管第二个参数是什么,结果必为 <code>NULL</code>。它不会报错,也不会尝试默认值。</p><p>常见踩坑场景:</p>
- 字段本身允许 NULL,又没加
IS NOT NULL过滤,导致结果集混入NULL - 用变量传参前未初始化,比如
DECLARE @dt DATETIME; SELECT EOMONTH(@dt);→ 返回NULL - 连接查询中某侧记录缺失,关联字段为
NULL,带入后整行结果“消失”在逻辑判断里
安全做法是提前判断或用 ISNULL/COALESCE 提供兜底:
SELECT EOMONTH(ISNULL(@input_date, GETDATE()), @offset)
兼容性与性能:别在 SQL Server 2008 或更老版本上硬套
EOMONTH 仅支持 SQL Server 2012 及以上版本,以及 Azure SQL Database。如果你的环境是 2008 R2 或更早,强行使用会报错:‘EOMONTH’ is not a recognized built-in function name。
替代方案不是写复杂表达式,而是用已知安全的组合:
- 当月最后一天:
DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1))) - 或者更简洁的旧式写法:
DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) + 1, 0))
不过只要环境允许,优先用 EOMONTH——它语义清晰、执行计划稳定、维护成本低。真正要留心的,反而是那些看似无关的隐式类型转换:比如把字符串 '2024-01' 直接传进去,SQL Server 会尝试转换,可能因语言设置不同而失败或出错。










