日历返回错误的月份

Han*_*ant 98 java calendar

Calendar rightNow = Calendar.getInstance();
String month = String.valueOf(rightNow.get(Calendar.MONTH));
Run Code Online (Sandbox Code Playgroud)

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

Vin*_*nie 130

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

  • 那是什么意思?它应该是一个日历而不是一个谜题.天数也正常,也是几年.你不认为Android开发人员犯了错误.是的,当然他们做了,他们不能纠正它只是因为它与数以百万计的旧应用程序不兼容. (19认同)
  • 这不是Android问题,而是Java问题. (6认同)

Boz*_*zho 28

他们从0开始 - 检查文档


Bar*_*ers 22

许多答案清楚地表明:月份从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()));
Run Code Online (Sandbox Code Playgroud)

输出:

11
Nov
November
Run Code Online (Sandbox Code Playgroud)

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


Mat*_*all 18

正如几位人士所指出的那样,Java中CalendarDate类返回的月数是从0而不是1索引的.所以0是1月,当前月11月是10.

你可能想知道为什么会这样.起源在于与POSIX标准功能ctime,gmtime并且localtime,它接受或返回一个time_t与以下字段(从结构的人3的ctime):

int tm_mday;    /* day of month (1 - 31) */
int tm_mon;     /* month of year (0 - 11) */
int tm_year;    /* year - 1900 */
Run Code Online (Sandbox Code Playgroud)

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


Fed*_*rer 11

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

因此Jan = 0,Feb = 1等.


b.r*_*oth 9

来自API:

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

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


Bas*_*que 7

TL;博士

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.
Run Code Online (Sandbox Code Playgroud)

细节

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

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

java.time

java.time框架是建立在Java 8和更高版本.这些类取代旧的麻烦日期时间类,如java.util.Date,.Calendar,和java.text.SimpleDateFormat.

现在处于维护模式,Joda-Time项目还建议迁移到java.time.

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

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

ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.

1月12日

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

LocalDate级表示没有时间一天和不同时区的日期,唯一的价值.

时区

时区对于确定日期至关重要.对于任何给定的时刻,日期在全球范围内因地区而异.例如,法国巴黎午夜过后几分钟是新的一天,而在魁北克蒙特利尔仍然是"昨天" .

指定适当的时区名称,格式continent/region,如America/Montreal,Africa/CasablancaPacific/Auckland.切勿使用3-4字母缩写,例如ESTIST因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!).

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

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

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

转换旧类

如果您GregorianCalendar手头有一个对象,请转换为ZonedDateTime使用toZonedDateTime添加到旧类的新方法.有关更多转换信息,请参阅将java.util.Date转换为"java.time"类型?

ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime();
int month = zdt.getMonthValue();  // Returns 1-12 as values.
Run Code Online (Sandbox Code Playgroud)

Month 枚举

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

Month month = today.getMonth();  // Returns an instant of `Month` rather than integer.
Run Code Online (Sandbox Code Playgroud)

Month枚举提供了有用的方法,如产生与一个String 月份的本地化名称.


关于java.time

java.time框架是建立在Java 8和更高版本.这些类取代麻烦的老传统日期时间类,如java.util.Date,Calendar,和SimpleDateFormat.

现在处于维护模式Joda-Time项目建议迁移到java.time类.

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

从哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在此比如找到一些有用的类Interval,YearWeek,YearQuarter,和更多.