java.util.Date到java.sql.Date转换给出了错误的月份

请考虑以下代码段:

Calendar futureDate = Calendar.getInstance(); int year = 2011; int month = 11; int day = 14; futureDate.set(year,month, day); System.out.println(futureDate.toString()); java.sql.Date sqlDate = new java.sql.Date( futureDate.getTime().getTime()); 

futureDate.toString()的打印输出是:

….. YEAR = 2011,月= 11,WEEK_OF_YEAR = 43,WEEK_OF_MONTH = 4,DAY_OF_MONTH = 14,DAY_OF_YEAR = 289,DAY_OF_WEEK = 1,DAY_OF_WEEK_IN_MONTH = 3,AM_PM = 0,HOUR = 11,HOUR_OF_DAY = 11,MINUTE = 32,SECOND = 51,微差= 117,ZONE_OFFSET = -18000000,DST_OFFSET = 3600000]

这表明Calendare对象保存了正确的日期。 但是,在转换为sql日期并存储在数据库(MySQL通过JDBC)之后,MySQL表显示此日期的“2011-12-14”而不是“2011-11-14”。 我会怀疑语言环境和时区,但这些会导致一天中的时间与日期的月份不一致。

我做错了什么线索?

Calendar#set(int, int, int)将month参数解释为从零开始,因此futureDate.set(2011, 11, 14)将日历的月份设置为12月。

TL;博士

 LocalDate.of( 2011 , 11 , 14 ) // November 14th, 2011 

细节

Matt Ball的回答是正确的。 但现在有一种改进的方式。

java.time

令人烦恼的旧日期时间类(如Calendarjava.util.Datejava.sql.Date现在已成为遗留问题,取而代之的是java.time类。

与遗留类不同,java.time类具有合理的编号 ,例如1月到12月的编号为1-12 ,星期一到星期日的编号 1-7。

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

 LocalDate ld = LocalDate.of( 2011 , 11 , 14 ) ; 

或者使用方便的Month枚举。

 LocalDate ld = LocalDate.of( 2011 , Month.NOVEMBER , 14 ) ; 

使用支持JDBC 4.2及更高版本的JDBC驱动程序,您可以将java.time对象直接传递给数据库。

 myPreparedStatement.setObject( … , ld ) ; 

获取时,使用getObject

 LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ; 

关于java.time

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

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

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

从哪里获取java.time类?

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

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