在Java编程中,获取当前月份是一个常见的需求,无论是用于业务逻辑处理、数据统计还是日期显示,Java提供了多种方式来获取当前月份,每种方式都有其适用场景和特点,本文将详细介绍几种主流的获取当前月份的方法,包括使用java.util.Date、java.util.Calendar、java.time包中的类以及第三方库如Joda-Time,并分析它们的优缺点及使用注意事项。

使用java.util.Date和SimpleDateFormat(传统方式)
在Java 8之前,java.util.Date和java.util.Calendar是处理日期时间的主要类,虽然Date类本身不直接提供获取月份的方法,但可以结合SimpleDateFormat或Calendar来实现。
1 通过SimpleDateFormat格式化获取
SimpleDateFormat是一个用于格式化和解析日期的具体类,可以通过定义日期模式来提取月份信息。
import java.text.SimpleDateFormat;
import java.util.Date;
public class CurrentMonthExample {
public static void main(String[] args) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("M"); // "M"表示月份(1-12)
String monthStr = sdf.format(date);
int month = Integer.parseInt(monthStr);
System.out.println("当前月份(1-12): " + month);
}
}
注意事项:
SimpleDateFormat不是线程安全的,在多线程环境下需要同步处理或使用ThreadLocal。- 月份范围是1-12,符合自然习惯,但需要注意
Date类已过时,官方不推荐在新代码中使用。
2 通过Calendar类获取
Calendar类提供了更丰富的日期操作方法,可以更灵活地获取年、月、日等信息。
import java.util.Calendar;
public class CalendarExample {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
int month = calendar.get(Calendar.MONTH) + 1; // 月份从0开始,需+1
System.out.println("当前月份(1-12): " + month);
}
}
注意事项:
Calendar的月份是从0开始的(0表示一月,11表示十二月),因此需要手动加1。Calendar类同样存在线程安全问题,且设计较为复杂,部分API已过时。
使用Java 8的java.time包(推荐方式)
Java 8引入了全新的日期时间API(java.time包),彻底解决了旧API的线程安全和设计缺陷问题,这是目前处理日期时间的最佳实践。

1 通过LocalDate获取
LocalDate表示一个不可变的日期对象,不包含时间信息,非常适合获取年、月、日。
import java.time.LocalDate;
import java.time.Month;
public class LocalDateExample {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
int monthValue = today.getMonthValue(); // 1-12
Month month = today.getMonth(); // 枚举类型,如Month.JANUARY
System.out.println("当前月份(数值): " + monthValue);
System.out.println("当前月份(枚举): " + month);
}
}
优点:
LocalDate是线程安全的,不可变对象。getMonthValue()直接返回1-12的数值,无需额外处理。getMonth()返回Month枚举,可读性更强,避免硬编码数字。
2 通过YearMonth获取(仅关注年月)
如果业务逻辑只需要年月信息(如账单周期),可以使用YearMonth类。
import java.time.YearMonth;
public class YearMonthExample {
public static void main(String[] args) {
YearMonth yearMonth = YearMonth.now();
int month = yearMonth.getMonthValue();
System.out.println("当前年月: " + yearMonth + ", 月份: " + month);
}
}
适用场景:
- 专注于年月操作,如计算月份差、判断是否为闰月等。
- 避免无关的日信息干扰,代码更简洁。
使用第三方库Joda-Time(兼容旧项目)
Joda-Time曾是Java日期时间的事实标准,即使在Java 8发布后,一些遗留项目仍在使用,其API设计直观易用。
import org.joda.time.DateTime;
import org.joda.time.Months;
public class JodaTimeExample {
public static void main(String[] args) {
DateTime dateTime = new DateTime();
int month = dateTime.getMonthOfYear(); // 1-12
System.out.println("当前月份(1-12): " + month);
}
}
注意事项:

- Joda-Time的月份已是从1开始的,符合自然习惯。
- 如果新项目启动,建议优先使用
java.time;维护旧项目时可根据需求选择。
不同方法的对比与选择
| 方法 | 线程安全 | 易用性 | 推荐度 | 适用场景 |
|---|---|---|---|---|
| SimpleDateFormat | 否 | 中 | 不推荐 | 简单格式化,需注意线程安全 |
| Calendar | 否 | 复杂 | 不推荐 | 旧项目维护 |
| java.time.LocalDate | 是 | 简单 | 强烈推荐 | Java 8+项目,通用场景 |
| YearMonth | 是 | 简单 | 推荐 | 仅需年月操作 |
| Joda-Time | 是 | 简单 | 兼容旧项目 | 遗留系统或需要特殊功能时 |
常见问题与解决方案
1 月份从0开始的问题
Calendar的月份从0开始,容易导致错误,解决方案:
- 使用
Calendar.MONTH + 1。 - 切换到
java.time.LocalDate,直接使用getMonthValue()。
2 线程安全问题
SimpleDateFormat和Calendar在多线程环境下可能抛异常,解决方案:
- 使用
ThreadLocal包装SimpleDateFormat。 - 优先选择
java.time包中的线程安全类。
3 时区处理
如果涉及跨时区业务,需注意时区设置:
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
int month = zonedDateTime.getMonthValue();
获取当前月份在Java中可以通过多种方式实现,从传统的Date和Calendar到现代的java.time包,对于新项目,强烈推荐使用java.time.LocalDate或YearMonth,它们不仅线程安全,而且API设计更符合直觉,维护旧项目时,可根据实际情况选择Calendar或Joda-Time,无论采用哪种方式,都需注意月份的起始值、线程安全以及时区处理,以确保代码的健壮性和可维护性。



















