1. 概述

在这个教程中,我们将学习如何在Java编程中计算给定年份中特定月份的天数。例如,对于代表2024年3月的输入,我们的代码将返回31

2. 使用 YearMonth

Java 8引入了全新的日期/时间API。特别是,它添加了YearMonth,一个表示年份和月份组合的不可变对象。

可以通过静态工厂方法of()轻松创建YearMonth实例。然后,我们可以调用其lengthOfMonth()方法,该方法会考虑年份,返回月份的长度:

int getDaysInMonthWithYearOfMonth(int month, int year) {
    YearMonth yearMonth = YearMonth.of(year, month);
    return yearMonth.lengthOfMonth();
}

现在,让我们用以下输入验证我们的方法结果:

  • 2024年3月有31天
  • 1999年11月有30天
  • 2025年2月有28天
  • 2004年2月有29天

由于我们把类命名为DaysInMonthUtils,我们可以编写单元测试:

@Test
void whenGetDaysInMonthWithYearOfMonth_thenCorrectResult() {
    assertEquals(31, new DaysInMonthUtils().getDaysInMonthWithYearOfMonth(3, 2024));
    assertEquals(30, new DaysInMonthUtils().getDaysInMonthWithYearOfMonth(11, 1999));
    assertEquals(28, new DaysInMonthUtils().getDaysInMonthWithYearOfMonth(2, 2025));
    assertEquals(29, new DaysInMonthUtils().getDaysInMonthWithYearOfMonth(2, 2004));
}

3. 使用 Calendar

对于Java 8之前的版本,我们可以退而求其次,使用原始的Calendar API

我们可以使用CalendargetInstance()方法获取默认时区和语言环境下的Calendar对象。然后,我们需要改变Calendar的日期和月份,最后调用getActualMaximum()方法,传入Calendar.DATE作为参数以获取结果:

int getDaysInMonthWithCalendar(int month, int year) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.DAY_OF_MONTH, 1);
    calendar.set(Calendar.YEAR, year);
    calendar.set(Calendar.MONTH, month - 1);
    return calendar.getActualMaximum(Calendar.DATE);
}

因为Calendar使用零基索引对月份进行计数,所以我们需要减去1。另一个值得注意的是,我们将月份的天数设为1。乍看之下这似乎没有目的,但这是因为Calendar会根据当前日期值调整日期。例如,假设我们有一个设置在7月31日的Calendar,如果我们将其月份改为6月,由于6月只有30天,API会滚到下一个有效日期,即7月1日。

现在,我们可以使用相同的测试输入来验证方法的行为:

@Test
void whenGetDaysInMonthWithCalendar_thenCorrectResult() {
    assertEquals(31, new DaysInMonthUtils().getDaysInMonthWithCalendar(3, 2024));
    assertEquals(30, new DaysInMonthUtils().getDaysInMonthWithCalendar(11, 1999));
    assertEquals(28, new DaysInMonthUtils().getDaysInMonthWithCalendar(2, 2025));
    assertEquals(29, new DaysInMonthUtils().getDaysInMonthWithCalendar(2, 2004));
}

4. 总结

在这篇文章中,我们使用YearMonth直接计算了月份的天数。我们也了解了如何绕过Calendar API的设计决策,确保使用它也能得到正确的结果。

如常,代码可以在GitHub上找到