日历返回错误的月份

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了日历返回错误的月份相关的知识,希望对你有一定的参考价值。

Calendar rightNow = Calendar.getInstance();
String month = String.valueOf(rightNow.get(Calendar.MONTH));

执行上面的代码片段后,month得到的值为10而不是11。为什么?

答案

月份的索引从0而不是1,因此10月份是11月份,11月份是12月份。

另一答案

他们从0开始 - 检查the docs

另一答案

许多答案清楚地表明:月份从0开始。

这里有一个提示:您应该使用SimpleDateFormat来获取月份的String表示:

Calendar rightNow = Calendar.getInstance();
java.text.SimpleDateFormat df1 = new java.text.SimpleDateFormat("MM");
java.text.SimpleDateFormat df2 = new java.text.SimpleDateFormat("MMM");
java.text.SimpleDateFormat df3 = new java.text.SimpleDateFormat("MMMM");
System.out.println(df1.format(rightNow.getTime()));
System.out.println(df2.format(rightNow.getTime()));
System.out.println(df3.format(rightNow.getTime()));

输出:

11
Nov
November

注意:输出可能会有所不同,它是特定于语言环境的。

另一答案

正如几位人士指出的那样,Java中CalendarDate类返回的月数从0而不是1开始。所以0是1月,当月是11月。

你可能想知道为什么会这样。起源于POSIX标准函数ctimegmtimelocaltime,它们接受或返回带有以下字段的time_t结构(来自man 3 ctime):

int tm_mday;    /* day of month (1 - 31) */
int tm_mon;     /* month of year (0 - 11) */
int tm_year;    /* year - 1900 */

这个API几乎完全复制到Java 1.0中的Java Date类中,并且从那里完全复制到Java 1.1中的Calendar类中。当他们介绍日历时,Sun解决了最明显的问题 - 格里高利历中的2001年由他们的日期类中的值101表示。但我不确定为什么他们没有将日期和月份值更改为至少两者在索引中保持一致,无论是从零还是一。到目前为止,这种不一致和相关的混淆仍然存在于Java(和C)中。

另一答案

月份从零开始,就像列表的索引一样。

因此Jan = 0,Feb = 1等。

另一答案

来自API:

一年中的第一个月是1月,即0;最后一个取决于一年中的月数。

http://java.sun.com/j2se/1.5.0/docs/api/java/util/Calendar.html

另一答案

tl;dr

LocalDate.now()            // Returns a date-only `LocalDate` object for the current month of the JVM’s current default time zone.
         .getMonthValue()  // Returns 1-12 for January-December.

Details

其他答案是正确但过时的。

麻烦的旧日期时间类有很多糟糕的设计选择和缺陷。一个是0-11月份的零点计数,而不是明显的1-12。

java.time

java.time框架内置于Java 8及更高版本中。这些类取代了旧的麻烦的日期时间类,如java.util.Date.Calendarjava.text.SimpleDateFormat

现在在maintenance modeJoda-Time项目也建议迁移到java.time。

要了解更多信息,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。

大部分java.time功能都在ThreeTen-Backport中反向移植到Java 6和7,并在ThreeTenABP中进一步适应android

ThreeTen-Extra项目使用其他类扩展了java.time。该项目是未来可能添加到java.time的试验场。

1月12日

在java.time中,月份数确实是1月到12月的预期1-12。

LocalDate类表示没有时间且没有时区的仅日期值。

时区

时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因地区而异。例如,在Paris France午夜过后几分钟是新的一天,而在Montréal Québec仍然是“昨天”。

proper time zone name的格式指定continent/region,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用诸如ESTIST之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
int month = today.getMonthValue();  // Returns 1-12 as values.

如果您想要时区的日期时间,请以相同的方式使用ZonedDateTime对象。

ZonedDateTime now = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );
int month = now.getMonthValue();  // Returns 1-12 as values.

转换旧类

如果您手头有GregorianCalendar对象,请使用添加到旧类的新ZonedDateTime方法转换为toZonedDateTime。有关更多转换信息,请参阅Convert java.util.Date to what “java.time” type?

ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime();
int month = zdt.getMonthValue();  // Returns 1-12 as values.

Month enum

顺便说一句,java.time类包括方便的Month enum。在代码中使用此类的实例而不仅仅是整数,以使代码更加自我记录,提供type-safety并确保有效值。

Month month = today.getMonth();  // Returns an instant of `Month` rather than integer.

Month枚举提供了有用的方法,例如使用localized name of the month生成String。


About java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,如java.util.DateCalendarSimpleDateFormat

现在在Joda-Timemaintenance mode项目建议迁移到java.time班。

要了解更多信息,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规格是JSR 310

从哪里获取java.time类?