如何使用带有 Calendar 对象的 AM PM 设置正确的时间?

How to set correct time with AM PM with Calendar object?

简单的问题,为什么这段代码的结果如下:

Calendar cal2 = Calendar.getInstance();
cal2.set(Calendar.HOUR, 12);
cal2.set(Calendar.AM_PM, Calendar.PM);
System.out.println(cal2.getTime().toString()); // Wed Jan 13 00:11:08 EET 2021
cal2.set(Calendar.AM_PM, Calendar.PM);
System.out.println(cal2.getTime().toString()); // Wed Jan 13 12:11:08 EET 2021
        
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR, 12);
cal.set(Calendar.AM_PM, Calendar.AM);
System.out.println(cal.getTime().toString()); // Tue Jan 12 12:11:08 EET 2021
cal.set(Calendar.AM_PM, Calendar.AM);
System.out.println(cal.getTime().toString()); // Tue Jan 12 00:11:08 EET 2021

第一个看起来是午夜 12 点,而不是下午。 第三个好像是中午12点,不是半夜

为什么多次设置日历AM或PM会改变结果? 如何正确设置时间?

Calendar.HOUR 接受 0-11 范围内的输入。它会将 12 环绕到 0。

使用 Calendar.HOUR_OF_DAY 来使用 0-23 之间的值。

日历非常混乱

您绝对不是第一个对 Calendar class 的工作原理感到困惑的人。幸运的是 class 也早就过时了。你不应该使用它。

Why setting calendar AM or PM multiple times change the result? …

为了按要求回答您的问题,Andi80 在另一个答案和评论中是正确的:HOUR 从 0 到 11。文档说 HOUR:

Field number for get and set indicating the hour of the morning or afternoon. HOUR is used for the 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12. E.g., at 10:04:15.250 PM the HOUR is 10.

当您第一次将小时设置为 12 并将 AM/PM 设置为下午时,应该预料到会出现异常,因为小时值超出了 运行ge。但是不,具有默认设置的 Calendar 对象不会给你那个。相反,它将时间设置为第二天凌晨 0 点; 1 月 13 日,当您 运行 1 月 12 日的代码时。根据 Calendar 逻辑,第 12 小时是第 11 小时之后的小时。

当你再次设置PM时,Calendar从你已经得到的时间,也就是上午,改成下午,所以你得到12:11:08,还是1月13号,隔天

为什么会计算两次时间?当你三次调用 set() 时不是一次也不是三次?这是 Calendar 的另一个令人困惑的特征。它计算你调用 getTime() 的时间(以及一些指定的其他方法)。在那一点上,它会拾取从调用 set() 到那一点为止的所有更改,并尽其所能将它们组合起来,如果有冲突则丢弃一些,使用任何头脑正常的人都不会想要的规则理解。

AM 的情况类似,所以我将详细信息留给 reader。

java.time

… How to set the time correctly?

我建议您使用 java.time,现代 Java 日期和时间 API,作为您的时间工作。如果您只想要中午 12 点或午夜 12 点,它们将作为常量内置:

    LocalTime t12Noon = LocalTime.NOON;
    System.out.println(t12Noon);
    
    LocalTime t12Midnight = LocalTime.MIDNIGHT;
    System.out.println(t12Midnight);

输出为:

12:00
00:00

A LocalTime 是一天中没有日期的时间。

如果您已经有时间并且只想调整小时和AM/PM,请使用with():

    LocalTime t12Noon = LocalTime.now(ZoneId.systemDefault())
            .with(ChronoField.CLOCK_HOUR_OF_AMPM, 12)
            .with(ChronoField.AMPM_OF_DAY, 1); // 1 = PM
    System.out.println(t12Noon);
    
    LocalTime t12Midnight = LocalTime.now(ZoneId.systemDefault())
            .with(ChronoField.CLOCK_HOUR_OF_AMPM, 12)
            .with(ChronoField.AMPM_OF_DAY, 0); // 0 = AM
    System.out.println(t12Midnight);
12:47:00.665155
00:47:00.669248

如果您也需要日期,请使用 ZonedDateTime 或其他合适的 class。 java.time 的所有日期时间 class 包括一天中的时间都具有相同的 with 方法,因此代码将相同。

如果您不可或缺地需要一个 Calendar 对象用于遗留 API 而您现在无法负担升级到 java.time 的费用,请使用 [=87] 中的 ZonedDateTIme =] 为你的时间数学。然后使用 GregorianCalendar.from(ZoendDateTIme) 转换为 Calendar 对象。

链接