Java 8 的 java.time API 推荐使用 YearMonth 获取指定月份首尾日:yearMonth.atDay(1) 得第一天,yearMonth.atEndOfMonth() 得最后一天;若从 LocalDate 推算,则用 withDayOfMonth(1) 和 with(TemporalAdjusters.lastDayOfMonth())。

Java 8 引入的 java.time API 提供了清晰、不可变、线程安全的方式来处理日期时间。获取指定月份的第一天和最后一天,推荐使用 YearMonth 类,它专为“年-月”精度设计,避免了手动计算天数或处理时区歧义的问题。
用 YearMonth 获取当月或指定月份的首尾日
YearMonth 是最直接的方式:它能精准表示某年某月,并提供 atDay(1) 和 lengthOfMonth() 方法快速得到第一天和最后一天。
- 获取指定年月的第一天:
yearMonth.atDay(1) - 获取指定年月的最后一天:
yearMonth.atEndOfMonth()(更简洁)或yearMonth.atDay(yearMonth.lengthOfMonth())
示例(2024 年 2 月):
YearMonth feb2024 = YearMonth.of(2024, 2); LocalDate firstDay = feb2024.atDay(1); // 2024-02-01 LocalDate lastDay = feb2024.atEndOfMonth(); // 2024-02-29(闰年)
从 LocalDate 动态推算当前/其他月份的首尾日
如果已有某个 LocalDate(比如用户输入的日期),想获取它所在月份的第一天和最后一天,可用 withDayOfMonth(1) 和 with(TemporalAdjusters.lastDayOfMonth()):
立即学习“Java免费学习笔记(深入)”;
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 第一天:
date.withDayOfMonth(1) - 最后一天:
date.with(TemporalAdjusters.lastDayOfMonth())
示例(基于 2023-07-15):
LocalDate ref = LocalDate.of(2023, 7, 15); LocalDate start = ref.withDayOfMonth(1); // 2023-07-01 LocalDate end = ref.with(TemporalAdjusters.lastDayOfMonth()); // 2023-07-31
扩展:获取上个月或下个月的首尾日
结合 plusMonths() 或 minusMonths(),可轻松跨月计算:
- 上个月第一天:
ref.minusMonths(1).withDayOfMonth(1) - 下个月最后一天:
ref.plusMonths(1).with(TemporalAdjusters.lastDayOfMonth())
注意:这些操作自动处理年份进位(如 2023-01-15.plusMonths(1) → 2023-02-15),无需手动判断。
不建议用 Calendar 或旧 Date API
尽管 Calendar 也能实现(如 set(DATE, 1)、getActualMaximum(DATE)),但它可变、线程不安全、API 冗长且易出错(例如月份从 0 开始)。新 API 更直观、不易误用,应作为首选。

















