Unerwünschte Automatische Zeit-Zone Umrechnung Mit Hibernate/JPA und JDK Datum
Bin ich mit Hibernate (4.2) als mein provider, und ich habe eine JPA-Entität, die ein Datumsfeld enthält:
@Entity
@Table(name = "MY_TABLE")
public class MyTable implements Serializable {
. . .
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "START_DATE")
private Date startDate;
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
. . .
}
Die entsprechende Spalte START_DATE ist definiert als START_DATE TIMESTAMP
(keine Zeitzone).
Ich bin mit Joda-Time (2.3) intern, um meine Anwendung zum Umgang mit dem Datum (immer in UTC), und kurz vor persistenten Entity, nutze ich die toDate()
Methode der Joda ist DateTime
- Klasse, um ein JDK Date
Objekt, um zu gehorchen, die Zuordnung:
public void myMethod(DateTime startDateUTC) {
. . .
MyTable table = /* obtain somehow */
table.setStartDate(startDateUTC.toDate());
. . .
}
Wenn ich mir in der DB auf den Wert, der gespeichert ist, merke ich, dass irgendwo (JDK? Hibernate?) wandelt den Datumswert mithilfe der Standard-Zeitzone der JVM, wo der code ausgeführt wird. In meinem Fall ist, dass "Amerika/Chicago".
Das problem wirklich manifestiert sich in der Nähe der Sommerzeit (DST). Zum Beispiel, wenn die Zeit intern ist
2014-03-09T02:55:00Z
es wird gespeichert, wie
09-Mar-14 03:55:00
Was ich möchte, ist für ihn gespeichert werden
09-Mar-14 02:55:00
Jedoch in CDT, 2:55AM am 9. März nicht vorhanden ("Spring forward"). So etwas (JDK? Hibernate?) rollt das Datum.
Ich möchte für den Augenblick, die gespeichert wird in der DB werden in UTC. Nachdem alle, das ist, wie ich bin im Umgang mit it-intern für meine Anwendung, aber sobald ich die hand aus, um beibehalten werden, es wird umgewandelt zu meiner Standard-Zeit-zone.
Hinweis: ich bin nicht in der Lage, um den Standard-Zeitzone mit
TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
, weil die JVM an, die bei mir läuft, ist von mehreren Anwendungen gemeinsam genutzt.
Wie Speichere ich das Datum im UTC-Format ohne Einstellung der JVM default-Zeitzone auf UTC?
- Meine Vermutung ist, dass, wenn man sich das Datum in der Datenbank, die Werkzeug, das Sie verwenden, um es zu betrachten, verwandelt sich der binäre, numerische Darstellung des Datums, den die Datenbank verwendet intern in etwas, das Sie verstehen können: ein Datum und eine Uhrzeit formatiert, die Ihre Zeitzone aus. Genau wie wenn Sie new Date().toString(): die Zeitzonen-Agnostiker Date-Objekt formatiert eine Zeichenkette mit der Standard-Zeitzone.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Lief ich in das selbst. Was ich sah ist, dass, obwohl Sie angegeben haben, UTC als Zeitzone in Ihrem Datum (und sehen diese durch drucken Sie es aus und sehen das 'Z' am Ende), für einige Grund, die JVM übernehmen möchte, und konvertieren Sie das Datum mithilfe der JVM die default-Zeitzone.
Sowieso, was Sie brauchen, ist eine benutzerdefinierte Zuordnung, dies zu umgehen. Versuchen Sie es mit Jadira:
Standardmäßig Jadira ist
PersistentDate
- Klasse verwendet die UTC Zeitzone, wenn es konvertiert das Datum bis auf die Millisekunde genau den Wert, der gespeichert wird in der DB. Sie können festlegen, dass andere Zeitzonen, aber es klingt wie UTC ist, was Sie speichern möchten.Als Kommentar zu Ihrem post schon sagt, manchmal ist das Werkzeug, das Sie verwenden, um die Abfrage der DB ist dabei die gedankenlos dumm automatische-wie-ist-meine-JDK-Standard-TZ-basierte Konvertierung für Sie, führt Sie zu glauben, der Wert ist immer noch falsch.
Sie können auch versuchen zum speichern der raw-Wert (als INTEGER) nur sich selbst davon zu überzeugen, dass die richtige Millisekunde Wert gespeichert wird.
HTH,
Mose
Gibt es einen Artikel über diese unerwartete Zeitverschiebung Frage, die Sie heraus überprüfen können hier. Es liefert die Erklärung für das problem an der Wurzel und zeigt, wie Sie damit umgehen. Natürlich, die wichtigste Annahme ist, dass wir wollen, dass zum speichern von Datumsangaben als UTC in der Datenbank.
Zum Beispiel, wenn Sie Lesen Sie ein Datum aus der Datenbank (sagen wir mal: 9:54 UTC), JDBC überspringt alle Informationen über die Zeitzone. Also, was JVM erhält durch JDBC ist ein Datum interpretiert, als ob es in der lokalen Zeitzone (in meinem Fall, 9:54 UTC+2). Wenn die lokale Zeitzone unterscheidet sich von der UTC - (und es in der Regel nicht), die wir am Ende mit der falschen Zeit-Verschiebung.
Die ähnliche situation tritt auf, wenn das schreiben in die DB.
Gibt es eine kleine open-source-Projekt DbAssist die Bereitstellung von Updates für verschiedene Versionen von Hibernate. Wenn Sie also mit Hibernate 4.2.21 fügen Sie einfach die folgenden Maven-Abhängigkeit zu Ihrem POM-Datei und dein problem ist gelöst (der genaue Installations-Anweisungen des setup mit z.B. Spring-Boot finden sich auf der Bibliothek github).
Nachdem Sie dieses Update angewendet haben, wird Ihr
java.util.Date
Felder in der entity-Klassen werden eingelesen und persistiert als erwartet: als wenn Sie gespeichert wurden, als UTC in der Datenbank. Wenn Sie mithilfe von JPA-Annotationen, die Sie nicht haben, ändern Sie die Zuordnung der Entitäten (wie in einem der vorherigen Antwort); es wird automatisch erledigt.Intern fix verwendet eine benutzerdefinierte UTC-Datum und-Art, die überschreibt Hibernate-Datum geben, um es zu zwingen, behandeln alle Daten in der DB als UTC. Klicken Sie dann auf anwenden, um die Zuordnung von
java.util.Date
zuUtcDateType
es nutzt@Typedef
annotation. Siehe unten:Wenn Ihr Projekt hängt von Hibernate HBM-Dateien oder andere Versionen von Hibernate, gehen Sie zu Projekt github wiki für detaillierte Anweisungen, wie zu installieren die passende Lösung.
Haben Sie versucht, zu verwenden getDateTime(DateTimeZone x) aus dem DateTime-Objekt?
Etwas wie dieses:
Hoffe es hilft dir!