Ich versuche, eine serverunabhängige Datumszeit in meiner Datenbank festzulegen, und ich glaube, dass die beste Vorgehensweise darin besteht, eine UTC-Datumszeit festzulegen. Mein DB-Server ist Cassandra und der DB-Treiber für Java versteht nur den Datumstyp.
Angenommen, ich verwende in meinem Code das neue Java 8 ZonedDateTime, um die UTC jetzt ( ZonedDateTime.now(ZoneOffset.UTC)
) abzurufen. Wie kann ich diese ZonedDateTime-Instanz in die Datumsklasse "Legacy" konvertieren?
java
java-8
java.util.date
datetime-conversion
zoneddatetime
Milen Kovachev
quelle
quelle
java.util.Date
undjava.sql.Date
.Antworten:
Sie können ZonedDateTime in einen Moment konvertieren, den Sie direkt mit Date verwenden können.
quelle
Date
ist eine Anzahl von Millisekunden seit der Epoche - also hängt es mit UTC zusammen. Wenn Sie es drucken , wird die Standardzeitzone verwendet, aber die Date-Klasse kennt die Zeitzone des Benutzers nicht ... Siehe beispielsweise den Abschnitt "Zuordnung" in docs.oracle.com/javase/tutorial/datetime/iso/legacy .html Und LocalDateTime ist explizit ohne Bezug auf eine Zeitzone - was als verwirrend angesehen werden kann ...ZonedDateTime
. Diejava.time.Instant
Klasse ist ein direkter Ersatz fürjava.util.Date
beide, die einen Moment in UTC darstellen, obwohlInstant
eine feinere Auflösung von Nanosekunden anstelle von Millisekunden verwendet wird.Date.from( Instant.now() )
hätte deine Lösung sein sollen. Oder genaunew Date()
das , was den gleichen Effekt hat und den aktuellen Moment in UTC erfasst.tl; dr
Obwohl dieser Code oben keinen Sinn hatte. Beide
java.util.Date
undInstant
repräsentieren einen Moment in UTC, immer in UTC. Der obige Code hat den gleichen Effekt wie:Kein Vorteil hier zu verwenden
ZonedDateTime
. Wenn Sie bereits eine habenZonedDateTime
, passen Sie UTC an, indem Sie a extrahierenInstant
.Andere Antwort richtig
Die Antwort von ssoltanid behandelt Ihre spezifische Frage, wie ein java.time-Objekt (
ZonedDateTime
) der neuen Schule in ein Objekt der alten Schule konvertiert werden kann, korrektjava.util.Date
. Extrahieren Sie dieInstant
aus der ZonedDateTime und übergeben Sie anjava.util.Date.from()
.Datenverlust
Beachten Sie, dass Sie einen Datenverlust erleiden , als
Instant
Spuren ns seit Epoche , währendjava.util.Date
Spuren Millisekunden seit Epoche.Ihre Frage und Ihre Kommentare werfen andere Fragen auf.
Server in UTC halten
Auf Ihren Servern sollte das Host-Betriebssystem generell auf UTC eingestellt sein. Die JVM übernimmt diese Host-Betriebssystemeinstellung als Standardzeitzone in den mir bekannten Java-Implementierungen.
Geben Sie die Zeitzone an
Sie sollten sich jedoch niemals auf die aktuelle Standardzeitzone der JVM verlassen. Anstatt die Hosteinstellung zu übernehmen, kann ein Flag, das beim Starten einer JVM übergeben wird, eine andere Zeitzone festlegen. Noch schlimmer: Jeder Code in einem Thread einer App kann jederzeit einen Aufruf tätigen
java.util.TimeZone::setDefault
, um diesen Standard zur Laufzeit zu ändern!Cassandra-
Timestamp
TypJede anständige Datenbank und jeder anständige Treiber sollte automatisch die Anpassung einer übergebenen Datums- und Uhrzeit an UTC zur Speicherung übernehmen. Ich benutze Cassandra nicht, aber es scheint eine rudimentäre Unterstützung für Datum und Uhrzeit zu haben. Die Dokumentation besagt, dass sein
Timestamp
Typ eine Anzahl von Millisekunden aus derselben Epoche ist (erster Moment von 1970 in UTC).ISO 8601
Darüber hinaus akzeptiert Cassandra Zeichenfolgeneingaben in den Standardformaten ISO 8601 . Glücklicherweise verwendet java.time die ISO 8601-Formate als Standard für das Parsen / Generieren von Zeichenfolgen. Die Implementierung der
Instant
KlassetoString
wird gut funktionieren.Präzision: Millisekunde gegen Nanosekord
Aber zuerst müssen wir die Nanosekundengenauigkeit von ZonedDateTime auf Millisekunden reduzieren. Eine Möglichkeit besteht darin, einen neuen Instant in Millisekunden zu erstellen. Glücklicherweise verfügt java.time über einige praktische Methoden zum Konvertieren in und aus Millisekunden.
Beispielcode
Hier ist ein Beispielcode in Java 8 Update 60.
Oder Sie können gemäß diesem Cassandra Java-Treiberdokument eine
java.util.Date
Instanz übergeben (nicht zu verwechseln mitjava.sqlDate
). Daraus können SieinstantTruncatedToMilliseconds
im obigen Code ein JuDate erstellen.Wenn Sie dies oft tun, können Sie einen Einzeiler erstellen.
Aber es wäre ordentlicher, eine kleine Dienstprogrammmethode zu erstellen.
Beachten Sie den Unterschied in all diesem Code als in der Frage. Der Code der Frage versuchte, die Zeitzone der ZonedDateTime-Instanz an UTC anzupassen. Das ist aber nicht nötig. Konzeptionell:
Wir extrahieren nur den Instant-Teil, der sich bereits in UTC befindet (im Grunde genommen in UTC, lesen Sie das Klassendokument für genaue Details).
Über java.time
Das java.time- Framework ist in Java 8 und höher integriert. Diese Klassen verdrängen die lästigen alten Legacy - Datum-Zeit - Klassen wie
java.util.Date
,Calendar
, &SimpleDateFormat
.Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu den Klassen java.time .
Weitere Informationen finden Sie im Oracle-Lernprogramm . Suchen Sie im Stapelüberlauf nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310 .
Sie können java.time- Objekte direkt mit Ihrer Datenbank austauschen . Verwenden Sie einen JDBC-Treiber, der mit JDBC 4.2 oder höher kompatibel ist . Keine Notwendigkeit für Strings, keine Notwendigkeit für
java.sql.*
Klassen.Woher bekomme ich die java.time-Klassen?
Das ThreeTen-Extra- Projekt erweitert java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen von java.time. Sie können einige nützliche Klassen hier wie finden
Interval
,YearWeek
,YearQuarter
, und mehr .quelle
Hier ist ein Beispiel für die Konvertierung der aktuellen Systemzeit in UTC. Dabei wird ZonedDateTime als String formatiert. Anschließend wird das String-Objekt mit java.text DateFormat in ein Datumsobjekt analysiert.
quelle
Wenn Sie den ThreeTen-Backport für Android verwenden und den neueren nicht verwenden können
Date.from(Instant instant)
(für den mindestens API 26 erforderlich ist), können Sie Folgendes verwenden:oder:
Bitte lesen Sie auch den Rat in der Antwort von Basil Bourque
quelle
DateTimeUtils
Klasse mit den Konvertierungsmethoden, daher würde ich Date date = DateTimeUtils.toDate (zdt.toInstant ()); `verwenden. Es ist nicht so niedrig.Sie können dies mit den in Java 8 und höher integrierten java.time- Klassen tun .
quelle
Instant
s Sekunden und Nanosekunden verfolgen.Date
s Spur Millisekunden. Diese Konvertierung von einem zum anderen ist korrekt.Ich benutze das.
Weil
Date.from(java.time.ZonedDateTime.ofInstant(now, zoneId).toInstant());
es nicht funktioniert !!! Wenn Sie Ihre Anwendung auf Ihrem Computer ausführen, ist dies kein Problem. Wenn Sie jedoch in einer Region von AWS, Docker oder GCP ausgeführt werden, tritt ein Problem auf. Weil Computer nicht Ihre Zeitzone in der Cloud ist. Sie sollten Ihre korrekte Zeitzone im Code einstellen. Zum Beispiel Asien / Taipeh. Dann wird es in AWS oder Docker oder GCP korrigiert.quelle
ans=Mon Jun 18 01:07:56 CEST 2018
, was falsch ist und was dannwrongAns=Sun Jun 17 17:07:56 CEST 2018
richtig ist.Die akzeptierte Antwort hat bei mir nicht funktioniert. Das zurückgegebene Datum ist immer das lokale Datum und nicht das Datum für die ursprüngliche Zeitzone. Ich lebe in UTC + 2.
Ich habe mir zwei alternative Möglichkeiten ausgedacht, um das richtige Datum aus einer ZonedDateTime zu erhalten.
Angenommen, Sie haben diese ZonedDateTime für Hawaii
oder für UTC wie ursprünglich gefragt
Alternative 1
Wir können java.sql.Timestamp verwenden. Es ist einfach, aber es wird wahrscheinlich auch Ihre Programmierintegrität beeinträchtigen
Alternative 2
Wir erstellen das Datum aus Millis ( hier früher beantwortet ). Beachten Sie, dass lokales ZoneOffset ein Muss ist.
quelle
Für eine Docker-Anwendung wie beehuang kommentiert sollten Sie Ihre Zeitzone einstellen.
Alternativ können Sie withZoneSameLocal verwenden . Beispielsweise:
2014-07-01T00: 00 + 02: 00 [GMT + 02: 00] wird konvertiert von
bis Di Jul 01 00:00:00 MESZ 2014 und bis
bis Montag, 30. Juni, 22:00:00 UTC 2014
quelle
Wenn Sie nur jetzt interessiert sind, dann verwenden Sie einfach:
quelle