JPA TemporalType.Date gibt ein falsches Datum an

8

Ich habe eine Klasse mit einem Datumsfeld, das ein "Gültig ab" -Datum für ein Stück Daten darstellt. Es ist wie folgt definiert:

%Vor%

Alles scheint gut zu funktionieren, genau an dem Punkt, wo ich das Datum aus der Datenbank herausziehe und es zeige. Wenn ich das Datum 18-Sep-2003 im Frontend wähle, dann speichere es, wenn ich in die Datenbank sicher genug einchecke, dass das Datum gehalten wird (Datenbank ist MySQL 5.5.9 Spaltentyp ist DATE). Wenn ich jedoch eine Liste abrufe, wird das Datum vom 17. September 2003 - einen Tag früher - angezeigt.

Wenn ich ein Datum früh oder spät im Jahr wie 26.03.2003 oder 25.12.2003 wähle, ist alles in Ordnung, also denke ich, dass dies etwas mit der Sommerzeit zu tun hat, aber wo schleicht sich der Fehler ein? Da die Datenbank das korrekte Datum zu halten scheint, muss es sein, wenn JPA wieder in eine java.util.Date konvertiert - ist java.util.Date die beste Klasse für ein Datum? Ich habe ein paar Beispiele gesehen, wo Leute Kalender benutzen, aber das scheint ziemlich schwer zu sein und ich bin mir nicht sicher, wie gut es mit einem JSF-basierten Frontend funktionieren wird.

    
wobblycogs 14.03.2011, 14:36
quelle

6 Antworten

5

Nach vielem Experimentieren und Suchen bin ich mir ziemlich sicher, dass ich die Ursache des Problems gefunden habe. Das Datum wird in einem java.util.Date festgehalten, das mit dem ganzen Gepäck der Zeit und einer Zeitzone kommt. Es scheint, dass JPA das Datum 18 Sep 2003 aus der Datenbank liest und dann das Datum wie folgt auffüllt: "Do 18 Sep 00:00:00 BST 2003" - Beachten Sie, dass die Zeitzone wahrscheinlich auf BST gesetzt wurde, weil dies nicht der Fall war explizit von der Datenbank festgelegt. Wie auch immer, es ist notwendig, die Ausgabe in der JSF-Seite zu formatieren, wenn Sie nur das Datum wie folgt sehen möchten:

%Vor%

Dies setzt jedoch voraus, dass die Zeitzone auf dem aktuellen Stand der Maschine liegt. In meinem Fall ist die Zeitzone momentan GMT (weil es Winter ist), also wenn sie mit dem Datum "Do 18. September 00:00:00 BST 2003" präsentiert wird, wird sie in GMT umgewandelt, indem eine Stunde subtrahiert wird und das Display den 17. September 2003 anzeigt.

    
wobblycogs 14.03.2011, 15:47
quelle
22

Sehr bedauerlich, aber alle bisherigen Antworten sind im Allgemeinen falsch. Die Antwort ist ziemlich einfach, erfordert aber, dass wir fünf Punkte trennen:

  1. DATE = java.sql.Date, das ist ein Wrapper um java.util.Date, das ist die Anzahl der Millisekunden seit der Epoche in der UTC-Zeitzone. Dies hat das Jahr / Monat / Datum / Stunden / Minuten / Sekunden in einer festen GMT + 0 (UTC) Zeitzone. Beachten Sie jedoch, dass java.sql.Date die Zeitkomponenten auf Null setzt!
  2. TIMESTAMP = java.sql.TimeStamp ist ein Komponentenwrapper um Date, der Bruchteile von Sekunden zur Unterstützung des SQL-DATE-Standardtyps hinzufügt. Diese Klasse / Typ ist nicht relevant oder benötigt für diese Frage, aber kurz gesagt, das hat das Datum plus die Zeit.
  3. Die Datenbank speichert DATE-Objekte wie definiert (unter Verwendung von UTC als Offset von Java), aber kann die Zeit übersetzen, wenn sie in der Datenbank so konfiguriert ist, dass sie sich in einer anderen Zeitzone befindet. Standardmäßig sind die meisten Datenbanken standardmäßig auf die Zeitzone des lokalen Servers eingestellt, was eine sehr schlechte Idee ist. Ladies, Gentlemen ... Speichern Sie IMMER DATE-Objekte in UTC. Lesen Sie weiter ...
  4. Die Zeit in der JVM und in der Zeitzone muss stimmen. Da das Date-Objekt UTC verwendet, wird ein Offset für Ihre Serverzeit berechnet? Berücksichtigen Sie dies mit der starken Empfehlung, dass die Serverzeit auf GMT + 0 (UTC) eingestellt sein sollte.
  5. Schließlich, wenn wir das DATUM aus der Datenbank (mit JSF oder was auch immer) rendern wollen, sollte als GMT + 0-Zeitzone eingerichtet werden, und wenn es von der Server-Up-Seite auch gemacht wird. Ihre Daten und Zeiten werden IMMER konsistent, referenziell und alle guten Dinge sein. Alles, was übrig bleibt, ist, die Zeit zu rendern und das ist, wo der Benutzer-Agent (für eine Web-Anwendung zum Beispiel) könnte verwendet werden, um die GMT + 0-Zeit in die "lokale" Zeitzone des Benutzers zu übersetzen .

Zusammenfassung: Verwenden Sie UTC (GMT + 0) auf dem Server in der Datenbank in Ihren Java-Objekten.

DATE und TIMESTAMP unterscheiden sich nur insofern von einer Datenbankperspektive, als TIMESTAMP zusätzliche Bruchteile von Sekunden enthält. Beide verwenden GMT + 0 (impliziert). JodaTime ist ein bevorzugtes Kalenderframework, um all dies zu behandeln, aber es wird nicht die Probleme der nicht übereinstimmenden JVM mit Datenbank-Zeitzoneneinstellungen beheben.

Wenn Anwendungsentwürfe von JVM in der DB GMT nicht verwenden, aufgrund von Tageslichteinsparungen, Uhranpassungen und allen Arten von anderen regionalen Spielen, die in der Welt lokale Uhren gespielt werden ... die Zeiten von Transaktionen und alles andere wird für immer verzerrt, nicht-referentiell, inkonsistent, etc.

Eine weitere gute Antwort zu Datentypen: java.util.Date vs java .sql.Date

Beachten Sie auch, dass Java 8 Updates mit besserer Datum / Uhrzeit-Handhabung (endlich) enthält, aber dies verhindert nicht, dass die Serveruhr, auf der die JVM läuft, in einer Zeitzone und die Datenbank in einer anderen ist. An diesem Punkt findet immer eine Übersetzung statt. In jedem großen (intelligenten) Client, mit dem ich arbeite, sind die Zeitzonen der Datenbank und des JVM-Servers aus genau diesem Grund auf UTC eingestellt, auch wenn ihre Operationen in einer anderen Zeitzone stattfinden.

    
Darrell Teague 04.02.2013 18:31
quelle
2
___ qstnhdr ___ JPA TemporalType.Date gibt ein falsches Datum an ___ answer5310041 ___

Ich hatte das gleiche Problem. Ich kenne den Grund nicht, aber mein Workaround war folgender:

In der Datenbank habe ich den Spaltentyp von %code% in %code% geändert.

In der Entitätsklasse habe ich die %code% Annotation geändert, aber den Datentyp %code% :

beibehalten %Vor%     
___ answer14693148 ___

Sehr bedauerlich, aber alle bisherigen Antworten sind im Allgemeinen falsch. Die Antwort ist ziemlich einfach, erfordert aber, dass wir fünf Punkte trennen:

  1. DATE = java.sql.Date, das ist ein Wrapper um java.util.Date, das ist die Anzahl der Millisekunden seit der Epoche in der UTC-Zeitzone. Dies hat das Jahr / Monat / Datum / Stunden / Minuten / Sekunden in einer festen GMT + 0 (UTC) Zeitzone. Beachten Sie jedoch, dass java.sql.Date die Zeitkomponenten auf Null setzt!
  2. TIMESTAMP = java.sql.TimeStamp ist ein Komponentenwrapper um Date, der Bruchteile von Sekunden zur Unterstützung des SQL-DATE-Standardtyps hinzufügt. Diese Klasse / Typ ist nicht relevant oder benötigt für diese Frage, aber kurz gesagt, das hat das Datum plus die Zeit.
  3. Die Datenbank speichert DATE-Objekte wie definiert (unter Verwendung von UTC als Offset von Java), aber kann die Zeit übersetzen, wenn sie in der Datenbank so konfiguriert ist, dass sie sich in einer anderen Zeitzone befindet. Standardmäßig sind die meisten Datenbanken standardmäßig auf die Zeitzone des lokalen Servers eingestellt, was eine sehr schlechte Idee ist. Ladies, Gentlemen ... Speichern Sie IMMER DATE-Objekte in UTC. Lesen Sie weiter ...
  4. Die Zeit in der JVM und in der Zeitzone muss stimmen. Da das Date-Objekt UTC verwendet, wird ein Offset für Ihre Serverzeit berechnet? Berücksichtigen Sie dies mit der starken Empfehlung, dass die Serverzeit auf GMT + 0 (UTC) eingestellt sein sollte.
  5. Schließlich, wenn wir das DATUM aus der Datenbank (mit JSF oder was auch immer) rendern wollen, sollte als GMT + 0-Zeitzone eingerichtet werden, und wenn es von der Server-Up-Seite auch gemacht wird. Ihre Daten und Zeiten werden IMMER konsistent, referenziell und alle guten Dinge sein. Alles, was übrig bleibt, ist, die Zeit zu rendern und das ist, wo der Benutzer-Agent (für eine Web-Anwendung zum Beispiel) könnte verwendet werden, um die GMT + 0-Zeit in die "lokale" Zeitzone des Benutzers zu übersetzen .

Zusammenfassung: Verwenden Sie UTC (GMT + 0) auf dem Server in der Datenbank in Ihren Java-Objekten.

DATE und TIMESTAMP unterscheiden sich nur insofern von einer Datenbankperspektive, als TIMESTAMP zusätzliche Bruchteile von Sekunden enthält. Beide verwenden GMT + 0 (impliziert). JodaTime ist ein bevorzugtes Kalenderframework, um all dies zu behandeln, aber es wird nicht die Probleme der nicht übereinstimmenden JVM mit Datenbank-Zeitzoneneinstellungen beheben.

Wenn Anwendungsentwürfe von JVM in der DB GMT nicht verwenden, aufgrund von Tageslichteinsparungen, Uhranpassungen und allen Arten von anderen regionalen Spielen, die in der Welt lokale Uhren gespielt werden ... die Zeiten von Transaktionen und alles andere wird für immer verzerrt, nicht-referentiell, inkonsistent, etc.

Eine weitere gute Antwort zu Datentypen: java.util.Date vs java .sql.Date

Beachten Sie auch, dass Java 8 Updates mit besserer Datum / Uhrzeit-Handhabung (endlich) enthält, aber dies verhindert nicht, dass die Serveruhr, auf der die JVM läuft, in einer Zeitzone und die Datenbank in einer anderen ist. An diesem Punkt findet immer eine Übersetzung statt. In jedem großen (intelligenten) Client, mit dem ich arbeite, sind die Zeitzonen der Datenbank und des JVM-Servers aus genau diesem Grund auf UTC eingestellt, auch wenn ihre Operationen in einer anderen Zeitzone stattfinden.

    
___ answer48397649 ___

Hatte das gleiche Problem mit SQL Server. Das Problem war ein alter SQL-JDBC-Treiber. Hatte sqljdbc4.jar vom April 2010, das mit SQL 2000 kompatibel war und das Problem hatte, dass Daten ein oder zwei Tage zurückgingen. Dann aktualisiert auf den neuesten Treiber oder sogar auf einen von 2012 und das Problem ging weg.

    
___ answer22695265 ___

Ich hatte das gleiche Problem, aber ich benutzte JSF 2 als Frontend. Wenn Sie JSF-Komponenten verwenden, sehen Sie sich diese andere Stackoverflow-Diskussion an und sehen Sie, dass JSF 2 nicht nach den erwarteten TimeZone-Regeln spielt. Die Designer haben es implementiert, um immer GMT zu verwenden. In meiner Situation hat dies dazu geführt, dass meine Daten in der Datenbank um 5 oder 6 Stunden deaktiviert waren, aber korrekt angezeigt wurden.

JSF convertDateTime rendert den vorherigen Tag

    
___ qstntxt ___

Ich habe eine Klasse mit einem Datumsfeld, das ein "Gültig ab" -Datum für ein Stück Daten darstellt. Es ist wie folgt definiert:

%Vor%

Alles scheint gut zu funktionieren, genau an dem Punkt, wo ich das Datum aus der Datenbank herausziehe und es zeige. Wenn ich das Datum 18-Sep-2003 im Frontend wähle, dann speichere es, wenn ich in die Datenbank sicher genug einchecke, dass das Datum gehalten wird (Datenbank ist MySQL 5.5.9 Spaltentyp ist DATE). Wenn ich jedoch eine Liste abrufe, wird das Datum vom 17. September 2003 - einen Tag früher - angezeigt.

Wenn ich ein Datum früh oder spät im Jahr wie 26.03.2003 oder 25.12.2003 wähle, ist alles in Ordnung, also denke ich, dass dies etwas mit der Sommerzeit zu tun hat, aber wo schleicht sich der Fehler ein? Da die Datenbank das korrekte Datum zu halten scheint, muss es sein, wenn JPA wieder in eine java.util.Date konvertiert - ist java.util.Date die beste Klasse für ein Datum? Ich habe ein paar Beispiele gesehen, wo Leute Kalender benutzen, aber das scheint ziemlich schwer zu sein und ich bin mir nicht sicher, wie gut es mit einem JSF-basierten Frontend funktionieren wird.

    
___ tag123mysql ___ MySQL ist ein freies, relationales Datenbank-Managementsystem (RDBMS), das die strukturierte Abfragesprache (SQL) verwendet. Verwenden Sie dieses Tag NICHT für andere DBs wie SQL Server, SQLite usw. Dies sind verschiedene DBs, die alle SQL verwenden, um die Daten zu verwalten. ___ tag123java ___ Java (nicht zu verwechseln mit JavaScript oder JScript oder JS) ist eine universelle objektorientierte Programmiersprache, die für die Verwendung in Verbindung mit der Java Virtual Machine (JVM) entwickelt wurde. "Java-Plattform" ist der Name für ein Computersystem, auf dem Tools zum Entwickeln und Ausführen von Java-Programmen installiert sind. Verwenden Sie dieses Tag für Fragen, die sich auf die Java-Programmiersprache oder Java-Plattform-Tools beziehen. ___ tag123jpa ___ Die Java Persistence API (JPA) ist eine Java-Spezifikation für den Zugriff, die Speicherung und die Verwaltung von Daten zwischen Java-Objekten / Klassen und einer relationalen Datenbank. Es ist Teil der EJB 3.0-Spezifikation und der Industriestandard für ORM (Object to Relational Mapping). ___ answer5300958 ___

Nach vielem Experimentieren und Suchen bin ich mir ziemlich sicher, dass ich die Ursache des Problems gefunden habe. Das Datum wird in einem java.util.Date festgehalten, das mit dem ganzen Gepäck der Zeit und einer Zeitzone kommt. Es scheint, dass JPA das Datum 18 Sep 2003 aus der Datenbank liest und dann das Datum wie folgt auffüllt: "Do 18 Sep 00:00:00 BST 2003" - Beachten Sie, dass die Zeitzone wahrscheinlich auf BST gesetzt wurde, weil dies nicht der Fall war explizit von der Datenbank festgelegt. Wie auch immer, es ist notwendig, die Ausgabe in der JSF-Seite zu formatieren, wenn Sie nur das Datum wie folgt sehen möchten:

%Vor%

Dies setzt jedoch voraus, dass die Zeitzone auf dem aktuellen Stand der Maschine liegt. In meinem Fall ist die Zeitzone momentan GMT (weil es Winter ist), also wenn sie mit dem Datum "Do 18. September 00:00:00 BST 2003" präsentiert wird, wird sie in GMT umgewandelt, indem eine Stunde subtrahiert wird und das Display den 17. September 2003 anzeigt.

    
___
Michael Glockenstein 19.03.2011 11:24
quelle
1

Ich hatte das gleiche Problem. Ich kenne den Grund nicht, aber mein Workaround war folgender:

In der Datenbank habe ich den Spaltentyp von DATE in DATETIME geändert.

In der Entitätsklasse habe ich die @Temporal Annotation geändert, aber den Datentyp Date :

beibehalten %Vor%     
Matt Handy 15.03.2011 09:54
quelle
1

Ich hatte das gleiche Problem, aber ich benutzte JSF 2 als Frontend. Wenn Sie JSF-Komponenten verwenden, sehen Sie sich diese andere Stackoverflow-Diskussion an und sehen Sie, dass JSF 2 nicht nach den erwarteten TimeZone-Regeln spielt. Die Designer haben es implementiert, um immer GMT zu verwenden. In meiner Situation hat dies dazu geführt, dass meine Daten in der Datenbank um 5 oder 6 Stunden deaktiviert waren, aber korrekt angezeigt wurden.

JSF convertDateTime rendert den vorherigen Tag

    
Revoman 27.03.2014 17:43
quelle
0

Hatte das gleiche Problem mit SQL Server. Das Problem war ein alter SQL-JDBC-Treiber. Hatte sqljdbc4.jar vom April 2010, das mit SQL 2000 kompatibel war und das Problem hatte, dass Daten ein oder zwei Tage zurückgingen. Dann aktualisiert auf den neuesten Treiber oder sogar auf einen von 2012 und das Problem ging weg.

    
Robert Niestroj 23.01.2018 08:57
quelle

Tags und Links