2012-08-13 70 views
3

我有以下情形:转换joda.time.DateTime以java.sql.Date并保留时区

  • 摇摆控制它返回一个Calendar对象
  • 中级DateTime对象,我用做重日期/时间操作(约达)
  • 数据库连接(OraclePreparedStatement),其仅需要一个java.sql.Date对象

我的概率lem是CalendarDateTime对象正在以格林尼治标准时间(我想要)正确显示日期,但是当我将其转换为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对象,同时保持正确的时区。我也做了不正确的转换也是完全可能的。

回答

15

浪费时间

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

“规范化”通过在特定的小时,分​​钟,秒和毫秒设置为零与实例关联的时区。

......根据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 2.4库可以帮助这里。将java.sql.Date或java.util.Date对象连同UTC time zone object一起传递给DateTime构造函数,以清楚地了解您挣扎的价值。

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 

要在另一方向乔达,时间java.util.Date转换...

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

要在另一方向乔达,时间转换java.sql.Date ...

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

更新 - 时间

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

java.util.Date的等价物是InstantInstant类表示UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数点后最多九(9)位数字)。

Instant instant = Instant.ofEpochMilli(1390276603054L); 

应用时区,ZoneId,产生ZonedDateTime这是类似于一个java.util.Calendar和乔达时间DateTime

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

现在提取一个日期只值,即ZonedDateTime的日期部分,如一个LocalDateLocalDate类表示没有时间和不带时区的仅限日期的值。所以LocalDate就是java.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通过使用添加到老班的新方法:toLocalDatevalueOf(LocalDate)

+0

什么是回来的路?是否:_new java.sql.Date(jodaDateTimeValue.withZone(DateTimeZone.UTC).getMillis())_? – 2014-02-20 09:41:58

+1

@ thomas.mc.work不,从Joda-Time DateTime对象到java.util.Date比这更容易......只需调用'toDate'方法即可。像这样:'java.util.Date date = myDateTime.toDate();'。对于java。** sql **。Date,您已经接近但不需要UTC,因为Millis始终是UTC。所以:'java.sql.Date date = new java.sql.Date(myDateTime.getMillis());' – 2014-02-20 09:46:54

+0

但是当我用这种方式从值“2014-02-01”的数据库转换java.sql.Date然后我得到“2014-01-31T23:00:00.000Z”(我的时区是CET)。当我使用时区CET时,它是正确的:“2014-02-01T00:00:00.000Z”。这是为什么? – 2014-02-20 13:23:52

1

我猜你可能需要在配置文件中添加TIMEZONE = GMT

在Web应用程序这在web.xml中定义

<context-param> <param-name>javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE</p‌​aram-name> <param-value>true</param-value> </context-param> 

问候

7

一个java.sql.Date的内部表示自1970年1月1日00:00:00.000 GMT以来经过的毫秒数。

您确定没有查看toString问题吗?方法toGMTString(),尽管折旧,仍然存在。

+0

这可能是问题,因为我已经疯狂发生java.util.Date.toString()及其时区信息的丢失。我会测试一些东西并回报。 – 2012-08-13 16:49:34