Java Gregorian Calendar返回错误的月份

所以我现在已经在这几个小时了,它返回正确的年份和日期,但由于一些奇怪的原因,它返回错误的月份。 我确定这是一个简单的修复,但我似乎无法弄明白。

package gregoriancalendar; import java.util.GregorianCalendar; public class Calendar8_5 { public static void main(String[] args){ GregorianCalendar calendar = new GregorianCalendar(); System.out.println("Current Year, Month & Date: "); System.out.println("Year is " + calendar.get(1)); System.out.println("Month is " + calendar.get(2)); System.out.println("Day is " + calendar.get(5)); calendar.setTimeInMillis(1234567898765L); //Elapse Time System.out.println("Set Value of 1234567898765L"); System.out.println("Year is " + calendar.get(1)); System.out.println("Month is " + calendar.get(2)); System.out.println("Day is " + calendar.get(5)); } } 

TL;博士

要获得当月的1-12号:

 LocalDate.now() .getMonthValue() 

最好指定所需/预期的时区。

 LocalDate.now( ZoneId.of( "America/Montreal" ) ).getMonthValue() 

同样调用.getYear().getDayOfMonth()

细节

它返回错误的月份

正如其他人所说,在Calendar,1月至12月的月份疯狂地编号为0-11而不是1-12。 旧日期时间类中许多糟糕的设计决策之一。 这些类现在已经遗留下来,取而代之的是java.time类。

那么有一项工作吗?

是的,有一个解决方法。 使用一个好的日期时间库而不是java.util.Date/Calendar的混乱。 现代的方法是使用java.time类。

当下时刻

获取当前日期和时间至关重要。 对于任何给定时刻,日期和挂钟时间因区域而异。

 ZoneId z = ZoneId.of( "America/Montreal" ); ZonedDateTime zdt = ZonedDateTime.now( z ); 

您可以通过Month枚举和月中查询各种组件,例如年份,月份编号,月份的本地化名称。

 System.out.println ( "Current: " + zdt ); System.out.println( "Year is " + zdt.getYear() ); System.out.println( "Month is " + zdt.getMonthValue() ); System.out.println( "Month name is " + zdt.getMonth().getDisplayName( TextStyle.FULL , Locale.CANADA_FRENCH ) ); // Or Locale.US, Locale.ITALY, etc. System.out.println( "Day is " + zdt.getDayOfMonth() ); 

当前:2016-12-14T04:54:44.802-05:00 [美国/蒙特利尔]

年是2016年

月份是12

月份名称为décembre

一天是14

查看IdeOne.com中的实时代码 。

如果您只关心日期而不关心时间,请使用LocalDate类。

 LocalDate.now( z ); 

具体时刻

您可以将时刻指定为自UTC 1970年第一时刻以来的毫秒数。

 long input = 1_234_567_898_765L ; Instant instant = Instant.ofEpochMilli( input ); 

instant.toString():2009-02-13T23:31:38.765Z

该输出中的ZZulu缩写,表示UTC 。

您可以指定时区以适应特定的挂钟时间。

 ZoneId z = ZoneId.of( "America/Montreal" ); ZonedDateTime zdt = instant.atZone( z ); 

zdt.toString():2009-02-13T18:31:38.765-05:00 [美国/蒙特利尔]

查看IdeOne.com中的实时代码 。

建议以这种方式交换日期时间数据。 最好序列化为ISO 8601格式的文本。 例如: 2009-02-13T23:31:38.765Z


关于java.time

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

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

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

从哪里获取java.time类?

  • Java SE 8SE 9及更高版本
    • 内置。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小function和修复。
  • Java SE 6SE 7
    • 许多java.timefunction都被反向移植到ThreeTen-Backport中的 Java 6和7。
  • Android的
    • ThreeTenABP项目特别适用于Android的ThreeTen-Backport (如上所述)。
    • 请参阅如何使用….

ThreeTen-Extra项目使用其他类扩展了java.time。 该项目是未来可能添加到java.time的试验场。 您可以在这里找到一些有用的课程,如IntervalYearWeekYearQuarter等。


老答案 – Joda-Time

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

  • 现在使用Joda-Time 2.3。
  • 在将来,使用Java 8,考虑转向JSR 310:日期和时间API ,它取代了日期/日历类,并受到Joda-Time的启发。

示例代码

今天

 // © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so. // import org.joda.time.*; // Generally best to be explicit about time zone rather than depend on default. DateTimeZone denverTimeZone = DateTimeZone.forID( "America/Denver" ); java.util.Locale locale = Locale.FRANCE; DateTime now = new DateTime( denverTimeZone ); System.out.println( "Current Year, Month & Day for: " + now ); System.out.println( "Year is " + now.year().getAsText( locale ) ); System.out.println( "Month is " + now.monthOfYear().getAsText( locale ) ); System.out.println( "Day is " + now.dayOfMonth().getAsText( locale ) ); System.out.println(); // blank line. 

跑的时候……

 Current Year, Month & Day for: 2013-12-04T01:58:24.322-07:00 Year is 2013 Month is décembre Day is 4 

有一天

 // Not generally a good idea to focus on integers for working with date-time, but you asked for it. DateTime someDateTime = new DateTime( 1234567898765L, DateTimeZone.UTC ); System.out.println( "Set Value of 1234567898765L is: " + someDateTime ); System.out.println( "Year is " + someDateTime.year().getAsText( locale ) ); System.out.println( "Month is " + someDateTime.monthOfYear().getAsText( locale ) ); System.out.println( "Day of month is " + someDateTime.dayOfMonth().getAsText( locale ) ); System.out.println( "Day of week is " + someDateTime.dayOfWeek().getAsText( locale ) ); System.out.println( "Day of year is " + someDateTime.dayOfYear().getAsText( locale ) ); 

跑的时候……

 Set Value of 1234567898765L is: 2009-02-13T23:31:38.765Z Year is 2009 Month is février Day of month is 13 Day of week is vendredi Day of year is 44 

PS当我注意到你的任意选择Long导致星期五第十三次时,我只是让我的背部发冷!

由于一些疯狂的原因, Calendar类使用从零开始的月份索引(Jan == 0,Feb == 1等),但所有其他日期部分都是基于一个(匹配其实际数字)。

据推测,它是在一些蹩脚的枚举尝试中完成的,但这只是愚蠢的。

我的建议是永远不要使用日历。 请改用Joda-Time 。

尝试使用Java 8提供的新日期和时间库,它们受Joda-Time的启发,易于使用。 它还解决了月份从0开始的问题。