2011-03-14 106 views
8

我有一個類有一個日期字段表示一個數據的「有效」日期。它的定義是這樣的:JPA TemporalType.Date給出錯誤的日期

@Temporal(TemporalType.DATE) 
private Date validFrom; 

一切似乎被罰款工作的權利了,我拉從數據庫中的日期和顯示的地步。如果我在前端選擇日期爲2003年9月18日的日期,那麼當我檢查數據庫的時候(即數據庫是MySQL 5.5.9列類型是DATE),保存它就足夠了。然而,當我拉起一份清單時,記錄的日期是2003年9月17日 - 前一天。

如果我在2003年3月26日或2003年12月25日選擇日期的早晚,一切都很好,所以我猜這是與夏令時有關,但錯誤在哪裏蔓延?由於數據庫似乎保持正確的日期,我猜它必須是當JPA轉換回java.util.Date - 是java.util.Date最適合日期的類嗎?我已經看到了幾個人們使用Calendar的例子,但是這個例子看起來非常重,我不確定它能夠在基於JSF的前端工作。

+0

'Date'解析爲什麼?我希望'java.util.Date'(正確的一個)而不是'java.sql.Date'?簡單的原因是,在編寫實體時,JPA試圖將實體屬性映射到數據庫列(和類型),而'java.sql.Date'已經是映射類型。所以你必須使用'java.util.Date'。另請注意,例如'p:calendar'(PrimeFaces)需要'java.util.Date'而不是'java.util.Calendar'(我自己碰到它)。請參閱:https://javabydeveloper.com/temporal/ – Roland 2017-10-25 09:03:46

回答

5

經過多次試驗和搜索,我很確定我找到了問題的原因。日期保存在一個java.util.Date中,它包含了所有的時間和時區。看起來JPA正在從數據庫中讀取日期爲2003年9月18日的日期,然後填入如下日期:「Thu Sep 18 00:00:00 BST 2003」 - 注意時區已設置爲BST,可能是因爲它不是由數據庫明確設置。無論如何,這是需要格式化的JSF頁面的輸出,如果你只希望看到這樣的日期:

<h:outputText value="#{t.validFrom}"> 
    <f:convertDateTime pattern="dd MMM yyyy"/> 
</h:outputText> 

然而,這假定時區是目前無論是在機器上力。在我的情況下,時區現在是格林威治標準時間(因爲它是冬天),所以當提供日期「Thu Sep 18 00:00:00 BST 2003」時,它將其轉換爲GMT,減去一小時,顯示器顯示2003年9月17日。

+0

取決於JPA實施。例如,DataNucleus允許用戶配置什麼時區來存儲事物。其他impls可能提供類似的東西 – DataNucleus 2011-03-14 16:47:44

+0

我目前正在使用EclipseLink,我很確定這不是問題的一部分。似乎正在發生的事情是轉換器元件假定它應該在GMT中顯示日期,即使它在BST中提供。 – wobblycogs 2011-03-14 20:03:22

+0

這可能不是一個很好的解決方案。如上所述,「...時區現在是GMT(因爲它是冬天......」 - 所以夏天在那個地區會發生什麼事情?)用牙齒和指甲打架,以保證格林尼治標準時間的GMT同步,沒有偏移或變化,其餘的否則在任何層上的移動時區總是會在未來某個時間點(可能未知的時間點)造成錯誤 – 2014-07-21 18:32:47

1

我有同樣的問題。不知道原因,但我的解決方法是以下幾點:

在數據庫中,我改變了列類型從DATEDATETIME

在實體類我改變了@Temporal註釋但保留了數據類型Date

@Temporal(TemporalType.TIMESTAMP) 
private Date myDate; 
2

但使用DATETIME,而不是日期將導致一個小時(或多個不同的時區)的區別,你如果你處理日期,可能會忽略,但不是時間值。 對我來說,來自mysql數據庫的數據是正確的值,但是當使用f:convertDateTime而沒有timeZone參數時導致默認使用GMT!

<h:outputText value="#{test.dt}"> 
    <f:convertDateTime pattern="yyyy-MM-dd HH:mm:ss" timeZone="CET"/> 
</h:outputText> 

工作正常,但我認爲這會工作沒有更多的時候,我們切換到CEST ....

+0

日期是在前面的例子中,「僅限日期」組件可能是「01/01/2003」,並且帶有一個隱含的時區,例如EST(由於日光節約時間而改變)。說這個交易日期不是依賴於時間的,即發生在中國的那個時候例如,當時在當地時區ACTUALLY 01/02/2003是不正確的。如果時區記錄爲UTC,則時間組件只能被忽略。即使這樣,在渲染日期時,也意味着時區是從該點向前的UTC,並且在任何其他時區的「哪一天」是「未知」。 – 2015-08-04 09:57:57

22

很抱歉,但所有的答案到目前爲止,一般都是不正確。 答案是很簡單,但要求我們分開五點:

  1. DATE = java.sql.Date,這是java.util.Date類的包裝是因爲大紀元在UTC毫秒數時區。因此,這具有固定的GMT + 0(UTC)時區中的年/月/日/時/分/秒。請注意,java.sql。日期將時間組件設置爲零!
  2. TIMESTAMP = java.sql.TimeStamp它是一個組件封裝器,它添加小數秒以支持SQL DATE類型標準。這個類/類型與這個問題無關或不需要,但總之這個日期加上時間。
  3. 數據庫存儲定義的DATE對象(使用UTC作爲Java的偏移量),但可能會將數據庫中配置的時間轉換爲不同的時區。默認情況下,大多數數據庫默認爲本地服務器時區,這是一個非常糟糕的主意。女士們,先生們......總是以UTC存儲DATE對象。請繼續閱讀...
  4. JVM和時區中的時間需要正確。由於Date對象正在使用UTC,因此您的服務器時間計算的偏移量是多少?考慮到強烈建議服務器時間設置爲GMT + 0(UTC)。
  5. 最後,當我們想從數據庫呈現日期(使用JSF或其他),它應該被設置爲GMT + 0時區,並且如果從服務器端完成也...您的日期和時間將永遠是一致的,指涉和所有的好東西。剩下的就是渲染時間,這就是將用戶代理(例如web應用)可能用將GMT + 0時間轉換爲用戶「本地」時區的地方。

摘要:在服務器上,在數據庫中,在Java對象中使用UTC(GMT + 0)。

DATE和TIMESTAMP僅與數據庫透視圖不同,因爲TIMESTAMP會攜帶更多秒的小數部分。兩者均使用GMT + 0(暗示)。 JodaTime是處理所有這些問題的首選日曆框架,但不會解決JVM不匹配到數據庫時區設置的問題。

如果從JVM到DB的應用程序設計不使用GMT,由於夏令時,時鐘調整以及在世界本地時鐘中播放的各種其他區域性遊戲......交易時間和其他所有事情將永遠被扭曲,非指稱,不一致等

有關數據類型的另一個好相關答案:java.util.Date vs java.sql.Date

還要注意的是Java的8有更好的日期/時間處理(最終)更新,但是這並不修復具有服務器時鐘的JVM運行在一個時區,數據庫在另一個時區。在這一點上總是有翻譯發生。在我使用的每個大型(智能)客戶端中,數據庫和JVM服務器時區都設置​​爲UTC,即使它們的操作主要發生在其他某個時區。

+0

我不明白爲什麼時區在這裏相關。有問題的領域是**日期** - 不包括小時信息。所以時區調整不應該影響結果。對我來說,它看起來像一個EclipseLink錯誤,因爲@wobblycogs在他的答案中暗示。 – gamliela 2015-05-07 15:37:50

+0

該問題引用了JPA Temporal類型和關聯的java.util.Date對象,其中包括一個時間組件。例如,僅僅看日間組件,目前它是5月9日在紐約,但5月10日在歐洲。因此是的,時間和時區始終是評估「什麼時候發生」事件的一個因素,就像發佈中所經歷的那樣。它不是特定於EclipseLink,因爲這種情況已經發生,並且將在所有JPA實現或實際上任何Java + DB環境中使用,因爲它們的基本時鐘參考可能位於不同的時區。 – 2015-05-10 04:00:58

+0

我同意當你問「什麼時候發生了什麼」時,時區是一個因素。例如,當「2015年5月10日」在地球上的特定地點開始。但只要我使用純粹的日期值,沒有確切的時間分量,「10/5/2015」的符號在所有地方都是一樣的。當然,有一個問題,當你在這個日期調用'getTime()'時會發生什麼,這就是事情與時區變得複雜的地方。 – gamliela 2015-05-10 08:47:07

1

我遇到了同樣的問題,但我使用JSF 2作爲前端。如果您使用的是JSF組件,請查看此其他stackoverflow討論,並看到JSF 2不按預期的TimeZone規則播放。設計人員將其實施爲始終使用GMT。在我的情況下,這導致我的日期在數據庫中關閉5或6個小時,但顯示正確。

JSF convertDateTime renders the previous day

+0

它實際上是基於服務器定義的時區進行轉換(而不是JSF)的JVM,如果與數據庫時區不同,則所有的投注都關閉以保持一致性。 – 2014-07-21 18:34:12

0

曾與SQL Server的同一問題。問題是一箇舊的SQL JDBC驅動程序。從2010年4月開始,sqljdbc4.jar與SQL 2000兼容,並且有日期回溯一兩天的問題。 然後更新到最新的驅動程序,甚至從2012年的一個,問題就消失了。