1. 概述

在这个简短教程中,我们将讲解如何在Java中获取给定月份的最后一天。

首先,我们将展示如何使用核心Java方法实现。然后,我们将通过Joda Time库来演示相同的目标。

2. Java 8 之前

在Java 8之前,DateCalendar类是处理时间和日期的常用选项。

通常,Calendar类提供了一套方法和常量,我们可以利用它们访问和操作诸如日期、月份和年份等时间信息

让我们来看看如何使用它来获取特定月份的最后一天:

static int getLastDayOfMonthUsingCalendar(int month) {
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.MONTH, month);
    return cal.getActualMaximum(Calendar.DAY_OF_MONTH);
}

如图所示,我们通过Calendar.getInstance()创建一个Calendar对象。接着,我们将日历的月份设置为指定的值。此外,我们使用getActualMaximum()方法和Calendar.DAY_OF_MONTH字段来获取月份的最后一天。

现在,让我们添加一个测试用例来验证我们的方法:

@Test
void givenMonth_whenUsingCalendar_thenReturnLastDay() {
    assertEquals(31, LastDayOfMonth.getLastDayOfMonthUsingCalendar(0));
    assertEquals(30, LastDayOfMonth.getLastDayOfMonthUsingCalendar(3));
    assertEquals(31, LastDayOfMonth.getLastDayOfMonthUsingCalendar(9));
}

这里需要注意的是,月份的值是基于零的。例如,一月的值为0,所以我们需要从想要的月份值中减去1。

3. Java 8 日期时间API

Java 8引入了许多新功能和改进。其中,我们有日期时间API这个API是为了克服旧API(基于DateCalendar类)的局限性而设计的

接下来,我们将深入探讨新API为获取月份最后一天提供的选项。

3.1. 使用YearMonth

处理月份的一种常见方式是使用YearMonth类。顾名思义,它表示一年中的某个月份。

这个类提供了atEndOfMonth()方法,返回一个LocalDate对象,表示给定月份的最后一天

让我们实战演示一下:

static int getLastDayOfMonthUsingYearMonth(YearMonth date) {
    return date.atEndOfMonth()
      .getDayOfMonth();
}

简而言之,我们使用atEndOfMonth()获取月份的最后一天,然后通过getDayOfMonth()获取返回的LocalDate对象的天数。

当然,我们也需要添加一个测试用例:

@Test
void givenMonth_whenUsingYearMonth_thenReturnLastDay() {
    assertEquals(31, LastDayOfMonth.getLastDayOfMonthUsingYearMonth(YearMonth.of(2023, 1)));
    assertEquals(30, LastDayOfMonth.getLastDayOfMonthUsingYearMonth(YearMonth.of(2023, 4)));
    assertEquals(31, LastDayOfMonth.getLastDayOfMonthUsingYearMonth(YearMonth.of(2023, 10)));
}

3.2. 使用TemporalAdjusters

另一种解决方案是使用TemporalAdjusters类。通常,这个类提供了一系列现成的静态方法,我们可以用来调整时间对象

一起看看如何使用它来获取LocalDate实例的最后一天:

static int getLastDayOfMonthUsingTemporalAdjusters(LocalDate date) {
    return date.with(TemporalAdjusters.lastDayOfMonth())
      .getDayOfMonth();
}

如上所示,类提供了调整器lastDayOfMonth()。它返回一个新的日期,设为该月的最后一天。

此外,我们使用getDayOfMonth()方法获取返回日期的天数。

接下来,我们将用一个测试用例确认我们的方法:

@Test
void givenMonth_whenUsingTemporalAdjusters_thenReturnLastDay() {
    assertEquals(31, LastDayOfMonth.getLastDayOfMonthUsingTemporalAdjusters(LocalDate.of(2023, 1, 1)));
    assertEquals(30, LastDayOfMonth.getLastDayOfMonthUsingTemporalAdjusters(LocalDate.of(2023, 4, 1)));
    assertEquals(31, LastDayOfMonth.getLastDayOfMonthUsingTemporalAdjusters(LocalDate.of(2023, 10, 1)));
}

4. Joda Time库

另外,我们可以使用Joda Time库达成同样的目的。在Java 8之前,它是日期时间处理的事实标准。首先,我们需要在pom.xml文件中添加Joda Time的依赖项:

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.12.5</version>
</dependency>

同样,Joda Time也提供了LocalDate类来表示日期。它包括withMaximumValue()方法,可以用来获取月份的最后一天

让我们实际操作一下:

static int getLastDayOfMonthUsingJodaTime(org.joda.time.LocalDate date) {
    return date.dayOfMonth()
      .withMaximumValue()
      .getDayOfMonth();
}

最后,我们再创建一个测试用例:

@Test
void givenMonth_whenUsingJodaTime_thenReturnLastDay() {
    assertEquals(31, LastDayOfMonth.getLastDayOfMonthUsingJodaTime(org.joda.time.LocalDate.parse("2023-1-1")));
    assertEquals(30, LastDayOfMonth.getLastDayOfMonthUsingJodaTime(org.joda.time.LocalDate.parse("2023-4-1")));
    assertEquals(31, LastDayOfMonth.getLastDayOfMonthUsingJodaTime(org.joda.time.LocalDate.parse("2023-10-1")));
}

不出所料,测试成功通过。

5. 总结

在这篇文章中,我们探讨了在Java中获取给定月份最后一天的不同方法。过程中,我们解释了如何使用核心Java实现。然后,我们展示了如何使用第三方库,如Joda Time。

如往常一样,本文使用的代码可以在GitHub找到。