日历返回错误的月份

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

在执行上面的代码片段之后,月份会得到10而不是11的值。怎么回事?

月份索引从0不是1,所以十一月份是十一月份,十一月份是十二月份。

他们从0开始 – 检查文档

许多答案显而易见:月份以0开头。

这里有一个提示:你应该使用SimpleDateFormat获取月份的string表示forms:

 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中的Calendar和Date类返回的月份是从0而不是1索引的。所以0是1月份,11月份是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介绍Calendar时,Sun解决了最明显的问题 – 2001年公历中的年份由Date类中的值101表示。 但我不确定为什么他们没有改变date和月份的值,至less在索引中都是一致的,无论是零还是一。 Java(和C)至今仍然存在这种不一致和相关的混淆。

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

所以Jan = 0,Feb = 1等

从API:

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

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

TL;博士

 LocalDate.now().getMonthValue() // Returns 1-12 for Jan-Dec. 

细节

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

麻烦的旧dateclass有许多糟糕的deviseselect和缺陷。 一个是从0到11的月份数字,而不是明显的1-12。

java.time

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

现在在维护模式下 , Joda-Time项目也build议迁移到java.time。

要了解更多信息,请参阅Oracle教程 。 并search堆栈溢出了很多例子和解释。

大部分的java.timefunction在ThreeTen- Backport中被移植到Java 6&7中,并在ThreeTenABP中进一步适用于Android。

ThreeTen-Extra项目将java.time扩展到其他类。 这个项目是未来可能增加java.time的一个试验场。

1-12个月

在java.time中,月份数量确实是1 – 12月份的1-12。

LocalDate类代表没有时间和没有时区的只有date的值。

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

如果您想要一个时区的date时间,以相同的方式使用ZonedDateTime对象。

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

如果手头有GregorianCalendar对象,则使用添加到旧类的新toZonedDateTime方法将其转换为ZonedDateTime 。 有关更多转换信息,请参阅将java.util.Date转换为什么“java.time”types?

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

Month枚举

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

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

Month枚举提供了有用的方法,例如使用本地化的月份名称生成String。

 cal.get(Calendar.MONTH) + 1; 

以上声明给出了确切的月份数字。 由于get(Calendar.Month)返回从0开始的月份,因此将结果加1会给出正确的输出。 并记住设置月份时减1。

 cal.set(Calendar.MONTH, (8 - 1)); 

或者使用提供的常量variables。

 cal.set(Calendar.MONTH, Calendar.AUGUST); 

这将是更好的使用

 Calendar.JANUARY 

这是零…