java - 将 joda.time.DateTime 转换为 java.sql.Date 并保留时区

标签 java date jdbc jodatime

我有以下场景:

  • 返回 Calendar 对象的 Swing 控件
  • 我用来进行大量日期/时间操作 (joda) 的中间 DateTime 对象
  • 只接受一个java.sql.Date对象的数据库连接(OraclePreparedStatement)

我的问题是 CalendarDateTime 对象正确显示 GMT 日期(我想要的),但是当我转换为 java.sql .Date为了发送到数据库,将日期转换为本地时区。

例如:

  • CalendarDateTime 是 2012-08-13T23:59:59.000Z(正确的 GMT)
  • 结果 java.sql.Date 是 2012-08-14(不正确的本地 UTC+2 日期)

下面是我用来进行转换的代码。

DateTime dateGmt = new DateTime(calendarGmt.getTimeInMillis(), DateTimeZone.UTC);
java.sql.Date sqlDate = new java.sql.Date(dateGmt.getMillis());

我不知道如何在保留正确时区的同时创建 java.sql.Date 对象。也完全有可能是我进行了错误的转换。

最佳答案

浪费时间

一个问题可能是 java.sql.Date 应该是……

'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.

…根据the documentation .这意味着,日期时间的时间部分正在从您的 java.util.Date 或 Joda-Time DateTime 对象中清除。

无时区

作为correct answer by Gilbert Le Blanc注意,java.util.Date 和 java.sql.Date 在内部都没有时区的概念。它们存储自 Unix epoch 以来的毫秒数.

这些类采用了讨厌的技巧:它们的toString 方法将JVM 的默认时区应用于字符串的呈现。非常混淆。 Date 对象没有时区,但当显示为字符串时,您会看到时区。

如果您的 java.util.Date 对象包含自纪元(1970 年开始)以来的 1344902399000L 毫秒数,这意味着 UTC/GMT 中的 2012-08-13T23:59:59.000Z。但是,如果您的 JVM 认为自己位于法国且实行夏令时 (DST),您将看到比 UTC/GMT 早 2 小时:2012-08-14T01:59:59.000+02:00 以该类糟糕的字符串格式描述。同一时刻在不同的时区具有不同的日期含义(13 对 14),墙上的时钟已经过了午夜。

Joda-Time 来拯救

Joda-Time 2.4 库在这里可以提供帮助。将 java.sql.Date 或 java.util.Date 对象传递给 DateTime构造函数以及 UTC time zone object清楚地了解您正在为之奋斗的值(value)。

java.util.Date date = new java.util.Date( 1390276603054L );
DateTime dateTimeUtc = new DateTime( date, DateTimeZone.UTC );
System.out.println( "dateTimeUtc: " + dateTimeUtc );

运行时...

2014-01-21T03:56:43.054Z

将另一个方向从 Joda-Time 转换为 java.util.Date ...

java.util.Date date = myDateTime.toDate();

将另一个方向从 Joda-Time 转换为 java.sql.Date ...

java.sql.Date date = new java.sql.Date( myDateTime.getMillis() );

更新 – java.time

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

java.util.Date 的等效项是 InstantInstant class 代表时间轴上的一个时刻 UTC分辨率为 nanoseconds (最多九 (9) 位小数)。

Instant instant = Instant.ofEpochMilli( 1390276603054L );

应用时区,ZoneId,生成一个类似于 java.util.Calendar 和 Joda-Time 的 ZonedDateTime 日期时间

ZoneId z = ZoneId.of( "Europe/Kaliningrad" );
ZonedDateTime zdt = instant.atZone( z );

现在提取一个仅限日期的值,即 ZonedDateTime 的日期部分,作为 LocalDateLocalDate class 表示没有时间和时区的仅日期值。所以 LocalDatejava.sql.Date 伪装成的:一个仅限日期的值。

LocalDate localDate = zdt.toLocalDate() ;

在 JDBC 4.2 及更高版本中,您可以通过 PreparedStatement::setObjectResultSet::getObject 将 java.time 类型直接与兼容的驱动程序一起使用。

myPreparedStatement.setObject( … , localDate );

……和……

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

对于较旧的不兼容驱动程序,通过使用添加到旧类的新方法将 java.sql.Date 对象短暂地转换为 LocalDate 或从 LocalDate 转换: toLocalDatevalueOf( LocalDate)

关于java - 将 joda.time.DateTime 转换为 java.sql.Date 并保留时区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11938111/

相关文章:

java - 尝试使用 jdbc 事务向数据库表输入值

java - 如何将 MySQL 命令的输出存储到 java 变量中 (JDBC)

java - 相同的查询在 MySQL 中工作,而不在 Java 客户端中工作

java - Spring Controller 将输出返回到 View 时出现错误

c# - C#计算两个日期之间的年月日

Swift 相当于 C gmtime?

java - Joda-Time - 天数不增加

java - 如何在 JSF + Spring + Hibernate 中使用 DTO

java - 为什么 Scala 很复杂?

java - Java 的类型删除有什么好处?