Ich versuche, eine serverunabhängige Datumszeit in meiner Datenbank festzulegen, und ich glaube, dass die beste Vorgehensweise darin besteht, eine UTC-DateTime festzulegen. Mein DB-Server ist Cassandra und der DB-Treiber für Java versteht nur den Date-Typ.
Angenommen, ich verwende in meinem Code die neue Java 8 ZonedDateTime, um die UTC jetzt abzurufen (ZonedDateTime.now(ZoneOffset.UTC)), wie kann ich diese ZonedDateTime-Instanz in die “alte” Date-Klasse konvertieren?
Es gibt zwei in Java eingebaute “Date”-Klassen, java.util.Date und java.sql.Date.
– Basilikum Bourque
28. August 2015 um 17:02 Uhr
Sie können ZonedDateTime in einen Instant umwandeln, den Sie direkt mit Date verwenden können.
Nein, es wird das aktuelle Datum in Ihrem Zonensystemstandard sein.
– Benutzer3460409
28. August 2015 um 15:53 Uhr
@MilenKovachev Ihre Frage macht keinen Sinn – ein Datum hat keine Zeitzone – es stellt nur einen Zeitpunkt dar.
– Assylias
28. August 2015 um 16:29 Uhr
@assylias Eigentlich macht deine Aussage keinen Sinn. Das Format, in dem die Uhrzeit gespeichert wird, impliziert eine Zeitzone. Das Datum basiert auf UTC, leider macht Java einige dumme Dinge und behandelt es nicht als solches, und betrachtet obendrein die Zeit als lokale TZ statt als UTC. Die Art und Weise, wie Data, LocalDateTime, ZonedDateTime Daten speichern, impliziert eine Zeitzone. Die Art und Weise, wie sie verwendet werden, ist, als ob TZs nicht existieren würden, was einfach falsch ist. java.util.Date hat implizit eine TZ des JVM-Standards. Die Tatsache, dass die Leute es als etwas anderes behandeln (einschließlich der Java-Dokumentation dafür!), Ist nur schlechte Leute.
– David
23. Oktober 2015 um 17:28 Uhr
@ David äh nein – a Date ist eine Anzahl von Millisekunden seit der Epoche – ist also auf UTC bezogen. Wenn du drucken it, wird die Standardzeitzone verwendet, aber die Date-Klasse hat keine Kenntnis von der Zeitzone des Benutzers … Siehe zum Beispiel 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 …
– Assylias
23. Oktober 2015 um 20:20 Uhr
Ihre Antwort beinhaltet unnötigerweise ZonedDateTime. Das java.time.Instant Klasse ist ein direkter Ersatz für java.util.Datedie beide jedoch einen Moment in UTC darstellen Instant verwendet eine feinere Auflösung von Nanosekunden anstelle von Millisekunden. Date.from( Instant.now() ) sollte deine Lösung gewesen sein. Oder einfach nur new Date() was den gleichen Effekt hat und den aktuellen Moment in UTC erfasst.
– Basilikum Bourque
16. Juli 2018 um 22:02 Uhr
Basil Bourque
tl;dr
java.util.Date.from( // Transfer the moment in UTC, truncating any microseconds or nanoseconds to milliseconds.
Instant.now() ; // Capture current moment in UTC, with resolution as fine as nanoseconds.
)
Obwohl der obige Code keinen Sinn hatte. Beide java.util.Date und Instant repräsentieren einen Moment in UTC, immer in UTC. Der obige Code hat die gleiche Wirkung wie:
new java.util.Date() // Capture current moment in UTC.
Kein Vorteil hier zu verwenden ZonedDateTime. Wenn Sie bereits eine haben ZonedDateTimepassen Sie sie an UTC an, indem Sie a extrahieren Instant.
java.util.Date.from( // Truncates any micros/nanos.
myZonedDateTime.toInstant() // Adjust to UTC. Same moment, same point on the timeline, different wall-clock time.
)
Andere Antwort Richtig
Die Antwort von ssoltanid befasst sich korrekt mit Ihrer spezifischen Frage, wie ein java.time-Objekt der neuen Schule konvertiert wird (ZonedDateTime) zu einer alten Schule java.util.Date Objekt. Extrahieren Sie die Instant aus ZonedDateTime und übergeben an java.util.Date.from().
Datenverlust
Beachten Sie, dass Sie werden Datenverlust erleidenwie Instant Spuren Nanosekunden seit Epoche während java.util.Date Spuren Millisekunden seit Epoche.
Ihre Frage und Kommentare werfen andere Probleme auf.
Halten Sie Server in UTC
Das Host-Betriebssystem Ihrer Server sollte als Best Practice im Allgemeinen auf UTC eingestellt sein. Die JVM übernimmt diese Host-Betriebssystemeinstellung als Standardzeitzone in den mir bekannten Java-Implementierungen.
Zeitzone angeben
Sie sollten sich jedoch niemals auf die aktuelle Standardzeitzone der JVM verlassen. Anstatt die Hosteinstellung zu übernehmen, kann ein beim Starten einer JVM übergebenes Flag eine andere Zeitzone festlegen. Schlimmer noch: Jeder Code in jedem Thread jeder App kann jederzeit einen Anruf tätigen java.util.TimeZone::setDefault um diese Voreinstellung zur Laufzeit zu ändern!
Kassandra Timestamp Typ
Irgendein anständige Datenbank und der Treiber sollte automatisch die Anpassung einer übergebenen Datum-Uhrzeit an UTC für die Speicherung vornehmen. Ich verwende Cassandra nicht, aber es scheint eine rudimentäre Unterstützung für Datum und Uhrzeit zu haben. Die Dokumentation sagt es Timestamp Typ ist eine Anzahl von Millisekunden aus derselben Epoche (erster Moment von 1970 in UTC).
ISO 8601
Darüber hinaus akzeptiert Cassandra Zeichenfolgeneingaben in der ISO 8601 Standardformate. Glücklicherweise verwendet java.time ISO 8601-Formate als Standard zum Analysieren/Generieren von Zeichenfolgen. Das Instant Klasse’ toString Umsetzung wird gut tun.
Präzision: Millisekunde vs. Nanosekunde
Aber zuerst müssen wir die Nanosekunden-Präzision von ZonedDateTime auf Millisekunden reduzieren. Eine Möglichkeit besteht darin, mithilfe von Millisekunden einen neuen Instant zu erstellen. Glücklicherweise verfügt java.time über einige praktische Methoden zum Konvertieren von und in Millisekunden.
Oder danach Cassandra Java-Treiber dockönnen Sie passieren a java.util.Date Beispiel (nicht zu verwechseln mit java.sqlDate). Daraus könnte man also ein JuDate machen instantTruncatedToMilliseconds im Code oben.
Beachten Sie den Unterschied in diesem ganzen Code als in der Frage. Der Code der Frage hat versucht, die Zeitzone der ZonedDateTime-Instanz an UTC anzupassen. Aber das ist nicht nötig. Konzeptionell:
ZonedDateTime = Instant + ZoneId
Wir extrahieren einfach den Instant-Teil, der bereits in UTC ist (im Grunde in UTC, lesen Sie das Klassendokument für genaue Details).
Weitere Informationen finden Sie unter Oracle-Tutorial. Und durchsuchen Sie Stack Overflow nach vielen Beispielen und Erklärungen. Spezifikation ist JSR310.
Sie dürfen umtauschen java.time Objekte direkt mit Ihrer Datenbank. Verwenden ein JDBC-Treiber gemäß JDBC 4.2 oder später. Keine Notwendigkeit für Saiten, keine Notwendigkeit für java.sql.* Klassen.
Spätere Versionen von Android-Bundle-Implementierungen der java.time Klassen.
Für frühere Android-Versionen (<26) ist die ThreeTenABP Projekt passt ThreeTen-Backport (oben erwähnt). Sehen Wie benutzt man ThreeTenABP….
Das ThreeTen-Extra project erweitert java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen zu java.time. Sie können hier einige nützliche Klassen finden, wie z Interval, YearWeek, YearQuarterund mehr.
Wunderbare Erklärung, gut detailliert. Ich danke dir sehr!
– Gianmarco F.
26. März 2019 um 8:50 Uhr
Danke @Basil Bourque für deine vollständige Antwort. Ist die Leistung schlecht oder beeinträchtigt, wenn die Liste oder die Paginierung zurückgegeben und diese Liste Element für Element durchlaufen wird, um von einer Zone (angenommen UTC) in eine andere Zone zu konvertieren?
– Entwickler152
28. Dezember 2021 um 19:50 Uhr
@devloper152 Fragst du nach der Leistung von java.time einen Moment nach Zeitzone anpassen? Versuch es selber. Ich nehme an, Sie werden es ziemlich schnell finden. Ich bezweifle, dass Sie finden werden java.time ein Flaschenhals sein.
– Basilikum Bourque
28. Dezember 2021 um 20:01 Uhr
Ich bin sehr zufrieden mit Ihrer Wiedergabe, die ich bereits ausprobiert habe. Eine andere Frage, Sir, was ist Ihre Meinung beim Konvertieren von einer Zone in eine andere in der Liste im Backend oder Frontend (Angular)?
– Entwickler152
28. Dezember 2021 um 20:12 Uhr
@devloper152 Ich verwende Angular nicht. Ich baue Web-Apps komplett in reinem Java mit Vaadin Flow.
– Basilikum Bourque
28. Dezember 2021 um 22:44 Uhr
David Rawson
Wenn Sie die verwenden ThreeTen Backport für Android und kann das neuere nicht verwenden Date.from(Instant instant) (was mindestens API 26 erfordert) können Sie verwenden:
ZonedDateTime zdt = ZonedDateTime.now();
Date date = new Date(zdt.toInstant().toEpochMilli());
oder:
Date date = DateTimeUtils.toDate(zdt.toInstant());
Bitte lesen Sie auch die Ratschläge in Basil Bourques Antwort
Der ThreeTen Backport (und ThreeTenABP) beinhalten a DateTimeUtils Klasse mit den Konvertierungsmethoden, also würde ich Date date = DateTimeUtils.toDate(zdt.toInstant());` verwenden. Es ist nicht so niedrig.
– Ole VV
17. Juni 2018 um 12:37 Uhr
Hier ist ein Beispiel für die Konvertierung der aktuellen Systemzeit in UTC. Dazu muss ZonedDateTime als String formatiert werden, und dann wird das String-Objekt mithilfe von java.text DateFormat in ein Datumsobjekt geparst.
ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC);
final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss");
final DateFormat FORMATTER_YYYYMMDD_HH_MM_SS = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
String dateStr = zdt.format(DATETIME_FORMATTER);
Date utcDate = null;
try {
utcDate = FORMATTER_YYYYMMDD_HH_MM_SS.parse(dateStr);
}catch (ParseException ex){
ex.printStackTrace();
}
Avec
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.
//This did not work for me
Date.from(java.time.ZonedDateTime.now().toInstant());
Ich habe mir zwei alternative Möglichkeiten ausgedacht, um das korrekte Datum von einer ZonedDateTime zu erhalten.
Angenommen, Sie haben diese ZonedDateTime für Hawaii
Sie können dies mit dem tun java.time Klassen, die in Java 8 und höher integriert sind.
ZonedDateTime temporal = ...
long epochSecond = temporal.getLong(INSTANT_SECONDS);
int nanoOfSecond = temporal.get(NANO_OF_SECOND);
Date date = new Date(epochSecond * 1000 + nanoOfSecond / 1000000);
Entschuldigung, woher kommen zeitliche und all diese Konstanten?
– Milen Kovachev
28. August 2015 um 15:30 Uhr
@MilenKovachev Eine ZonedDateTime ist eine Instanz von Temporal
– Peter Lawrey
28. August 2015 um 15:43 Uhr
Danke, aber Sie hätten erwähnen sollen, dass Sie Ihre Antwort bearbeitet haben, damit mein Kommentar nicht albern erscheint.
– Milen Kovachev
28. August 2015 um 15:44 Uhr
@MilenKovachev Sie können einen Kommentar löschen, aber es ist keine dumme Frage.
– Peter Lawrey
28. August 2015 um 15:45 Uhr
Ich kann nicht verstehen, warum diese Antwort abgelehnt wurde. Instants verfolgen Sekunden und Nanosekunden. Dates verfolgen Millisekunden. Diese Umrechnung von einem zum anderen ist richtig.
– scottb
29. August 2015 um 0:34 Uhr
13332300cookie-checkWie konvertiere ich ZonedDateTime in Date?yes
Es gibt zwei in Java eingebaute “Date”-Klassen,
java.util.Date
undjava.sql.Date
.– Basilikum Bourque
28. August 2015 um 17:02 Uhr