2012-08-13 71 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