为什么 java.util.Calendar 在 2021 年 2 月返回 31?

Mic*_*chi 1 java calendar date java-time

以下代码段返回:

28
31
Run Code Online (Sandbox Code Playgroud)

我想不通,为什么。我尝试通过两种方式将日历对象设置为 2021 年 2 月,我做错了什么?月份是从零开始的,所以二月是“1”。

import java.util.Calendar;
import java.util.GregorianCalendar;

public class HelloWorld{

     public static void main(String []args){
        Calendar g = new GregorianCalendar(2021, 1, 28);
        System.out.println(g.getActualMaximum(Calendar.DAY_OF_MONTH));
        

        int year = 2021;
        int month = 1;
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, month);
        System.out.println(c.getActualMaximum(Calendar.DAY_OF_MONTH));
     }
}
Run Code Online (Sandbox Code Playgroud)

或者这只会发生,因为我在 3 月 29、30 或 31 日调用 Calendar.getInstance() 而我没有调用

c.set(Calendar.DAY_OF_MONTH, {any day below 29});
Run Code Online (Sandbox Code Playgroud)

Arv*_*ash 6

java.util日期时间 API 及其格式化 APISimpleDateFormat已过时且容易出错。建议完全停止使用它们并切换到现代日期时间 API *

使用现代日期时间 API:

import java.time.Month;
import java.time.Year;

public class Main {
    public static void main(String[] args) {
        System.out.println(YearMonth.of(2021, Month.FEBRUARY).lengthOfMonth());
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

28
Run Code Online (Sandbox Code Playgroud)

Trail: Date Time 中了解有关现代日期时间 API 的更多信息。

使用旧版 API:

import java.util.Calendar;
import java.util.GregorianCalendar;

public class Main {
    public static void main(String[] args) {
        // 1st Feb 2021
        Calendar cal = new GregorianCalendar(2021, Calendar.FEBRUARY, 1);
        System.out.println(cal.getActualMaximum(Calendar.DAY_OF_MONTH));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

28
Run Code Online (Sandbox Code Playgroud)

* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用ThreeTen-Backport,它将大部分java.time功能向后移植到 Java 6 和 7。如果您正在为 Android 项目和您的 Android API 工作级别仍然不符合 Java-8,请检查通过 desugaringHow to use ThreeTenABP in Android Project可用的 Java 8+ APIs

  • 不会 [`YearMonth.of(2021, Month.FEBRUARY)`](https://docs.oracle.com/javase/8/docs/api/java/time/YearMonth.html#of-int-java. time.Month-) 比 `Year.of(2021).atMonth(Month.FEBRUARY)` 更简单?--- 它肯定会跳过“Year”对象的浪费创建。 (2认同)

And*_*eas 5

您调用Calendar.getInstance(),它返回一个Calendar初始化为当前时间的对象,今天意味着 2021 年 3 月 31 日。

然后设置YEAR为 2021 和MONTH1(二月),保留DAY_OF_MONTH为 31。如果您向Calendar对象询问日期,它将解析这些字段并返回一个解释问题的日期值:

System.out.println(c.getTime()); // prints: Wed Mar 03 11:51:55 EST 2021
Run Code Online (Sandbox Code Playgroud)

看到上面写着“ 2021 年3 月 3 日”吗?这是因为 2 月 31 日会在 2 月 28 日之后滚动,成为 3 月 3 日。

由于该Calendar对象现在是三月,因此c.getActualMaximum(Calendar.DAY_OF_MONTH)正确返回 31。

要正确执行此操作,请调用clear()并设置DAY_OF_MONTH为 1,当您使用 Niceset(year, month, date)辅助方法时,这会容易得多。

int year = 2021;
int month = Calendar.FEBRUARY/*1*/;
Calendar c = Calendar.getInstance();
c.clear();
c.set(year, month, 1);
System.out.println(c.getTime()); // prints: Mon Feb 01 00:00:00 EST 2021
System.out.println(c.getActualMaximum(Calendar.DAY_OF_MONTH)); // prints: 28
Run Code Online (Sandbox Code Playgroud)