tl; dr
Instant
und LocalDateTime
sind zwei völlig verschiedene Tiere: Eines repräsentiert einen Moment, das andere nicht.
Instant
repräsentiert einen Moment, einen bestimmten Punkt in der Zeitleiste.
LocalDateTime
repräsentiert ein Datum und eine Uhrzeit. Ohne eine Zeitzone oder einen Versatz von UTC kann diese Klasse jedoch keinen Moment darstellen . Es repräsentiert potenzielle Momente in einem Bereich von etwa 26 bis 27 Stunden, dem Bereich aller Zeitzonen rund um den Globus.
Falsche Vermutung
LocalDateTime
ist eher eine Datums- / Uhrendarstellung einschließlich Zeitzonen für Menschen.
Ihre Aussage ist falsch: A LocalDateTime
hat keine Zeitzone . Keine Zeitzone zu haben, ist der ganze Punkt dieser Klasse.
Um diese Klasse zu zitieren 'doc:
Diese Klasse speichert oder repräsentiert keine Zeitzone. Stattdessen handelt es sich um eine Beschreibung des Datums, wie es für Geburtstage verwendet wird, kombiniert mit der Ortszeit, wie sie auf einer Wanduhr angezeigt wird. Es kann keinen Moment auf der Zeitachse ohne zusätzliche Informationen wie einen Versatz oder eine Zeitzone darstellen.
Bedeutet Local…
also "nicht in Zonen unterteilt, kein Versatz".
Instant
An Instant
ist ein Moment auf der Zeitachse in UTC , eine Anzahl von Nanosekunden seit der Epoche des ersten Moments von 1970 UTC (im Grunde genommen siehe Klassendokument für Details). Da der größte Teil Ihrer Geschäftslogik, Datenspeicherung und des Datenaustauschs in UTC erfolgen sollte, ist dies eine praktische Klasse, die häufig verwendet wird.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
OffsetDateTime
Die Klassenklasse OffsetDateTime
repräsentiert einen Moment als Datum und Uhrzeit mit einem Kontext von einigen Stunden-Minuten-Sekunden vor oder hinter UTC. Der Versatzbetrag, die Anzahl der Stunden-Minuten-Sekunden, wird durch die ZoneOffset
Klasse dargestellt.
Wenn die Anzahl der Stunden-Minuten-Sekunden Null ist, OffsetDateTime
repräsentiert a einen Moment in UTC, der mit a identisch ist Instant
.
ZoneOffset
Die ZoneOffset
Klasse repräsentiert einen Versatz von UTC , eine Anzahl von Stunden-Minuten-Sekunden vor UTC oder hinter UTC.
A ZoneOffset
ist nur eine Anzahl von Stunden-Minuten-Sekunden, nichts weiter. Eine Zone ist viel mehr und hat einen Namen und eine Historie von Änderungen am Versatz. Die Verwendung einer Zone ist daher immer der Verwendung eines bloßen Versatzes vorzuziehen.
ZoneId
Eine Zeitzone wird durch die ZoneId
Klasse dargestellt.
In Paris bricht beispielsweise früher ein neuer Tag an als in Montréal . Wir müssen also die Zeiger der Uhr bewegen, um den Mittag (wenn die Sonne direkt über uns steht) für eine bestimmte Region besser wiederzugeben . Je weiter von der UTC-Linie in Westeuropa / Afrika nach Osten / Westen entfernt, desto größer ist der Versatz.
Eine Zeitzone ist ein Satz von Regeln für den Umgang mit Anpassungen und Anomalien, wie sie von einer lokalen Gemeinde oder Region praktiziert werden. Die häufigste Anomalie ist der allzu beliebte Wahnsinn, der als Sommerzeit (DST) bekannt ist .
In einer Zeitzone wird die Geschichte vergangener Regeln, gegenwärtiger Regeln und Regeln für die nahe Zukunft bestätigt.
Diese Regeln ändern sich häufiger als erwartet. Stellen Sie sicher, dass Sie die Regeln Ihrer Datums- / Uhrzeitbibliothek, normalerweise eine Kopie der 'tz'-Datenbank , auf dem neuesten Stand halten. In Java 8 ist es jetzt einfacher als je zuvor, auf dem neuesten Stand zu bleiben, da Oracle ein Timezone Updater Tool veröffentlicht .
Geben Sie einen richtigen Zeitzonennamen im Format Continent/Region
, wie zum Beispiel America/Montreal
, Africa/Casablanca
oder Pacific/Auckland
. Verwenden Sie niemals die Abkürzung für 2-4 Buchstaben wie EST
oder, IST
da es sich nicht um echte Zeitzonen handelt, die nicht standardisiert und nicht einmal eindeutig (!) Sind.
Zeitzone = Versatz + Anpassungsregeln
ZoneId z = ZoneId.of( “Africa/Tunis” ) ;
ZonedDateTime
Stellen Sie sich ZonedDateTime
konzeptionell als Instant
mit einem zugewiesenen vor ZoneId
.
ZonedDateTime = (Instant + ZoneId)
So erfassen Sie den aktuellen Moment in der Wanduhrzeit, die von den Menschen einer bestimmten Region (einer Zeitzone) verwendet wird:
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Pass a `ZoneId` object such as `ZoneId.of( "Europe/Paris" )`.
Fast Ihr gesamtes Backend, Ihre Datenbank, Ihre Geschäftslogik, Ihre Datenpersistenz und Ihr Datenaustausch sollten sich in UTC befinden. Für die Präsentation für Benutzer müssen Sie sich jedoch auf eine vom Benutzer erwartete Zeitzone einstellen. Dies ist der Zweck der ZonedDateTime
Klasse und der Formatierungsklassen, die zum Generieren von String-Darstellungen dieser Datums- / Uhrzeitwerte verwendet werden.
ZonedDateTime zdt = instant.atZone( z ) ;
String output = zdt.toString() ; // Standard ISO 8601 format.
Sie können Text in lokalisiertem Format mit generieren DateTimeFormatter
.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ;
String outputFormatted = zdt.format( f ) ;
mardi 30 avril 2019 à 23 h 22 min 55 s heure de l'Inde
LocalDate
, LocalTime
,LocalDateTime
Die „local“ Datum Zeitklassen, LocalDateTime
, LocalDate
, LocalTime
, sind eine andere Art von Lebewesen. Sie sind nicht an einen Ort oder eine Zeitzone gebunden. Sie sind nicht an die Zeitachse gebunden. Sie haben keine wirkliche Bedeutung, bis Sie sie auf einen Ort anwenden, um einen Punkt auf der Zeitachse zu finden.
Das Wort "Lokal" in diesen Klassennamen kann für Uneingeweihte kontraintuitiv sein. Das Wort bedeutet jeden Ort oder jeden Ort, aber keinen bestimmten Ort.
Daher werden für Geschäftsanwendungen die "lokalen" Typen nicht häufig verwendet, da sie nur die allgemeine Vorstellung eines möglichen Datums oder einer möglichen Uhrzeit darstellen, nicht eines bestimmten Zeitpunkts auf der Zeitachse. Business-Apps kümmern sich in der Regel um den genauen Zeitpunkt, zu dem eine Rechnung eingeht, ein Produkt für den Transport versendet wird, ein Mitarbeiter eingestellt wurde oder das Taxi die Garage verließ. Daher verwenden Entwickler von Geschäftsanwendungen Instant
und ZonedDateTime
Klassen am häufigsten.
Wann würden wir also verwenden LocalDateTime
? In drei Situationen: Wenn wir ein bestimmtes Datum und eine bestimmte Uhrzeit auf mehrere Standorte anwenden möchten, wenn wir Termine buchen oder wenn wir eine beabsichtigte, aber unbestimmte Zeitzone haben. Beachten Sie, dass keiner dieser drei Fälle ein bestimmter Punkt auf der Zeitachse ist. Keiner dieser Fälle ist ein Moment.
Eine Tageszeit, mehrere Momente
Manchmal möchten wir eine bestimmte Tageszeit an einem bestimmten Datum darstellen, diese jedoch auf mehrere Orte in verschiedenen Zeitzonen anwenden.
Zum Beispiel ist "Weihnachten beginnt am 25. Dezember 2015 um Mitternacht" ein LocalDateTime
. Mitternachtsstreiks in Paris zu anderen Zeitpunkten als in Montréal und wieder anders in Seattle und Auckland .
LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ; // 00:00:00
LocalTime ldt = LocalDateTime.of( ld , lt ) ; // Xmas morning anywhere.
Ein weiteres Beispiel: "Die Acme Company hat die Richtlinie, dass die Mittagszeit in jeder ihrer Fabriken weltweit um 12:30 Uhr beginnt LocalTime
." Um eine echte Bedeutung zu haben, müssen Sie sie auf die Zeitachse anwenden, um den Moment von 12:30 in der Stuttgarter Fabrik oder 12:30 in der Rabat- Fabrik oder 12:30 in der Sydney- Fabrik zu berechnen .
Buchungstermine
Eine andere Situation LocalDateTime
ist die Buchung zukünftiger Veranstaltungen (z. B. Zahnarzttermine). Diese Termine könnten in Zukunft weit genug entfernt sein, dass Sie das Risiko eingehen, dass Politiker die Zeitzone neu definieren. Politiker geben oft wenig oder gar keine Warnung. Wenn Sie "15.00 Uhr am 23. Januar" meinen, unabhängig davon, wie die Politiker mit der Uhr spielen, können Sie keinen Moment aufzeichnen - das würde bedeuten, dass 15.00 Uhr zu 14.00 Uhr oder 16.00 Uhr wird, wenn diese Region die Sommerzeit einführt oder fallen lässt. beispielsweise.
Speichern Sie für Termine a LocalDateTime
und a ZoneId
, die separat aufbewahrt werden. Später, wenn Sie einen Zeitplan erstellen, bestimmen Sie spontan einen Moment, indem Sie aufrufen LocalDateTime::atZone( ZoneId )
, um ein ZonedDateTime
Objekt zu generieren .
ZonedDateTime zdt = ldt.atZone( z ) ; // Given a date, a time-of-day, and a time zone, determine a moment, a point on the timeline.
Bei Bedarf können Sie auf UTC einstellen. Extrahieren Sie eine Instant
aus dem ZonedDateTime
.
Instant instant = zdt.toInstant() ; // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.
Unbekannte Zone
Einige Personen verwenden sie möglicherweise LocalDateTime
in einer Situation, in der die Zeitzone oder der Versatz unbekannt ist.
Ich halte diesen Fall für unangemessen und unklug. Wenn eine Zone oder ein Versatz beabsichtigt, aber unbestimmt ist, haben Sie schlechte Daten. Das wäre so, als würde man einen Produktpreis speichern, ohne die beabsichtigte Währung zu kennen. Keine gute Idee.
Alle Datums- und Uhrzeittypen
Der Vollständigkeit halber finden Sie hier eine Tabelle aller möglichen Datums- und Uhrzeittypen, sowohl moderne als auch ältere in Java, sowie diejenigen, die durch den SQL-Standard definiert sind. Dies kann dazu beitragen, die Instant
& LocalDateTime
Klassen in einen größeren Kontext zu stellen.
Beachten Sie die ungeraden Entscheidungen, die das Java-Team beim Entwerfen von JDBC 4.2 getroffen hat. Sie haben sich dafür entschieden, alle java.time- Zeiten zu unterstützen… mit Ausnahme der beiden am häufigsten verwendeten Klassen: Instant
& ZonedDateTime
.
Aber keine Sorge. Wir können leicht hin und her konvertieren.
Konvertieren Instant
.
// Storing
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
// Retrieving
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;
Konvertieren ZonedDateTime
.
// Storing
OffsetDateTime odt = zdt.toOffsetDateTime() ;
myPreparedStatement.setObject( … , odt ) ;
// Retrieving
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZone( z ) ;
Ü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 Zeichenfolgen, 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 .