我有以下场景:
- 返回
Calendar
对象的 Swing 控件 - 我用来进行大量日期/时间操作 (joda) 的中间
DateTime
对象 - 只接受一个
java.sql.Date
对象的数据库连接(OraclePreparedStatement
)
我的问题是 Calendar
和 DateTime
对象正确显示 GMT 日期(我想要的),但是当我转换为 java.sql .Date
为了发送到数据库,将日期转换为本地时区。
例如:
Calendar
和DateTime
是 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
的等效项是 Instant
。 Instant
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
的日期部分,作为 LocalDate
。 LocalDate
class 表示没有时间和时区的仅日期值。所以 LocalDate
是 java.sql.Date
伪装成的:一个仅限日期的值。
LocalDate localDate = zdt.toLocalDate() ;
在 JDBC 4.2 及更高版本中,您可以通过 PreparedStatement::setObject
和 ResultSet::getObject
将 java.time 类型直接与兼容的驱动程序一起使用。
myPreparedStatement.setObject( … , localDate );
……和……
LocalDate ld = myResultSet.getObject( … , LocalDate.class );
对于较旧的不兼容驱动程序,通过使用添加到旧类的新方法将 java.sql.Date
对象短暂地转换为 LocalDate
或从 LocalDate
转换: toLocalDate
和 valueOf( LocalDate)
。
关于java - 将 joda.time.DateTime 转换为 java.sql.Date 并保留时区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11938111/