Wie bekomme ich Standard ZoneOffset in Java8?

77

Mit Java8 wissen wir, dass die Verwendung ZoneId.default()den Systemstandard erreichen kann ZoneId, aber wie kann man den Standard erhalten ZoneOffset?

Ich sehe, dass a ZoneIdeinige "Regeln" hat und jede Regel a hat. Bedeutet das ZoneOffset, dass a ZoneIdmehr als eine haben kann ZoneOffset?

FredSuvn
quelle
versuchenZoneOffset.systemDefault()
Shubham Chaurasia
2
Viele Zeitzonen haben aufgrund der Sommerzeit unterschiedliche Offsets.
Marc Philipp
15
ZoneOffset.systemDefault()gibt jedoch a zurück ZoneId.
Marc Philipp
3
Das aktuelle ZoneOffset ist eine Funktion von ZoneId und Instant. ZoneOffset current = zone.getRules().getOffset(instant)
Alexander Yanyshin
3
@FredSuvn Ich glaube, Yanys kommt zu dem Konzept, dass es keinen Sinn macht, nach einem Offset zu fragen, ohne eine Zeitzone und einen Moment (einen Datums- / Zeitwert) anzugeben. Beispiel: Die Sommerzeit in America/Los_Angelesbewirkt, dass der Versatz -08:00aktuell ist, sich jedoch -07:00im Sommer ändert . Sie können also keinen Offset anfordern, ohne zu sagen, wann und für welche Zeitzone . Weitere Informationen finden Sie in meiner Antwort .
Basil Bourque

Antworten:

179

tl; dr

OffsetDateTime.now().getOffset()

Sie sollten jedoch wahrscheinlich eher eine Zeitzone als nur einen Versatz von UTC verwenden.

ZoneId.systemDefault() 

Versatz gegen Zeitzone

Ein Versatz von UTC besteht lediglich aus einer Anzahl von Stunden, Minuten und Sekunden - nichts weiter. Bedeutet beispielsweise -08:00acht Stunden hinter der UTC und +05:45fünf Stunden und fünfundvierzig Minuten vor der UTC .

Eine Zeitzone ist eine Geschichte vergangener, gegenwärtiger und zukünftiger Änderungen des Versatzes , den die Menschen einer bestimmten Region verwenden. Anomalien wie die Sommerzeit (DST), die zu Verschiebungen des Versatzes über bestimmte Zeiträume führen, werden im Laufe der Zeit verfolgt, in der Vergangenheit und in der Zukunft, wenn Politiker geplante Änderungen angekündigt haben.

Verwenden Sie daher besser eine Zone, wenn dies bekannt ist.

Der Versatz für jede Region variiert im Laufe der Zeit. Beispielsweise verschiebt die Sommerzeit in den USA den Versatz für etwa ein halbes Jahr um eine Stunde und stellt diese Stunde dann in der anderen Jahreshälfte wieder auf den Versatz zurück. Der gesamte Zweck einer Zeitzone besteht darin, diese Verschiebungen im Versatz zu dokumentieren.

Es macht also wirklich keinen Sinn, nach einem Offset ohne Datum und Uhrzeit zu fragen . In einem America/Los_AngelesTeil dieses Jahres ist der Offset beispielsweise -08:00in einem anderen Teil des Jahres -07:00während der Sommerzeit.

OffsetDateTime

Geben wir also einen Moment als an OffsetDateTimeund extrahieren Sie dann den ZoneOffset.

OffsetDateTime odt = OffsetDateTime.now ();
ZoneOffset zoneOffset = odt.getOffset ();

odt.toString (): 2017-01-02T15: 19: 47.162-08: 00

zoneOffset.toString (): -08: 00

Diese nowMethode wendet implizit die aktuelle Standardzeitzone der JVM an. Ich schlage vor, dass Sie dies immer explizit machen, indem Sie Ihre gewünschte / erwartete Zeitzone angeben. Auch wenn Sie die aktuelle Standardzone möchten, sagen Sie dies ausdrücklich, um Ihre Absichten klar zu machen. Beseitigen Sie die Unklarheit darüber, ob Sie die Standardeinstellung beabsichtigt haben oder die Zeitzone nicht berücksichtigt haben, wie dies bei Programmierern so häufig der Fall ist. Rufen Sie an ZoneId.systemDefault.

OffsetDateTime odt = OffsetDateTime.now ( ZoneId.systemDefault () );
ZoneOffset zoneOffset = odt.getOffset ();

ZoneId.systemDefault (). ToString (): America / Los_Angeles

odt: 2017-01-02T15: 19: 47.162-08: 00

zoneOffsetOfOdt: -08: 00

Eine Warnung bezüglich der Abhängigkeit von der Standardzone: Diese Standardeinstellung kann jederzeit durch einen beliebigen Code in einem beliebigen Thread innerhalb der JVM geändert werden. Wenn wichtig, fragen Sie den Benutzer nach der beabsichtigten Zeitzone.

Sie können den Versatz nach seiner Zeitdauer als Gesamtanzahl von Sekunden fragen.

int offsetSeconds = zoneOffset.getTotalSeconds ();

offsetSeconds: -28800

ZonedDateTime

Ein weiteres Beispiel: Vielleicht möchten Sie wissen, wie hoch der Offset am diesjährigen Weihnachtstag in Québec sein wird. Geben Sie die Zeitzone an America/Montreal, holen Sie sich a ZonedDateTimeund fragen Sie nach dem Versatz als ZoneOffsetObjekt.

ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate ld = LocalDate.of( 2017 , 12 , 25 );
ZonedDateTime zdtXmas = ld.atStartOfDay( z );
ZoneOffset zoneOffsetXmas = zdtXmas.getOffset();

zdtXmas.toString (): 2017-12-25T00: 00-05: 00 [Amerika / Montreal]

zoneOffsetXmas.toString (): -05: 00

zoneOffsetXmas.getTotalSeconds (): -18000

Tabelle der Datums- und Uhrzeittypen in Java, sowohl modern als auch alt.

ZoneId

Wie im Kommentar von yanys vorgeschlagen, können Sie a ZoneIdfür eine bestimmte Person abfragen, ZoneOffsetindem Sie einen Moment als Instant. Die InstantKlasse repräsentiert einen Moment auf der Zeitachse in UTC mit einer Auflösung von Nanosekunden (bis zu neun (9) Stellen eines Dezimalbruchs).

Dies ist nur eine weitere Route zum selben Ziel. Genau wie bei OffsetDateTimeund ZonedDateTimeoben diskutiert geben wir (a) eine Zeitzone und (b) einen Moment an.

Instant instant = zdtXmas.toInstant();
ZoneOffset zo = z.getRules().getOffset( instant );

Für ZoneId: America / Montreal zum Zeitpunkt: 2017-12-25T05: 00: 00Z ist das ZoneOffset: -05: 00

Sehen Sie den Code all dieser Beispiele live auf IdeOne.com .

ZoneOffset.systemDefault - Bug oder Feature?

Die ZoneOffsetKlasse, eine Unterklasse von ZoneId, wird als Erbe der systemDefaultMethode dokumentiert . Dies funktioniert jedoch nicht wirklich.

ZoneOffset zoneOffset = ZoneOffset.systemDefault() ;  // Fails to compile.

Fehler: Inkompatible Typen: ZoneId kann nicht in ZoneOffset konvertiert werden

Ich bin mir nicht sicher, ob es sich bei diesem Kompilierungsfehler um einen Fehler oder eine Funktion handelt. Wie oben erläutert, scheint es mir nicht sinnvoll zu sein, jemals nach einem Standardversatz mit Datum und Uhrzeit zu fragen. Vielleicht ZoneOffset.systemDefaultsollte dies tatsächlich fehlschlagen. In der Dokumentation sollte dies jedoch mit einer Erklärung angegeben werden.

Ich habe versucht, einen Fehler zu melden, wenn das Dokument dieses Problem nicht behoben hat, habe jedoch aufgegeben und konnte nicht feststellen, wo und wie ein solcher Fehlerbericht eingereicht werden soll.

Sonnenzeit versus politische Zeit

Ein bisschen mehr über Offsets und Zeitzonen…

Sonnenzeit seit der Vorgeschichte verwendet, jeden Tag Tracking mit der Feststellung , wenn die Sonne direkt über ist. Stecke einen Stock in den Boden und beobachte seinen Schatten. Wenn der Schatten am kürzesten ist, wenn der Schatten eher zu wachsen als zu schrumpfen beginnt, dann wissen Sie, dass es jetzt Mittag ist. Formalisieren Sie dies mit einer Sonnenuhr , um den Stundenablauf zu verfolgen.

Mit der Sonnenzeit, wenn Sie von Stadt zu Stadt nach Westen reisen, kommt der Mittag etwas später. Wenn Sie nach Osten gehen, kommt der Mittag etwas früher. So hat jede Stadt ihren eigenen Mittag, der nur mit Städten im Norden und Süden auf derselben Länge geteilt wird.

Die Sonnenzeit wurde in der Neuzeit weitgehend aufgegeben. Als Züge, Telegraphen und Telefone eintrafen, musste auch zeitlich koordiniert werden. So wurde ein Punkt für die nahe Sonnenzeit des Mittags ausgewählt, und ein großer Landstrich, der so viele Meilen westlich und östlich liegt, soll alle 12:00 Uhr auf der Uhr teilen, die gleiche Anzahl von Stunden vor uns oder hinter der Greenwich Prime Meridian Linie . So begann die Tradition, dass an jeder Haltestelle an prominenter Stelle eine Uhr angezeigt wurde, um die Stadt über die Standardzeit für ihre größere Region und nicht über die Sonnenzeit für ihre eigene Stadt zu informieren . Im Allgemeinen Städte in der westlichen Rand dieser Zeitzone Region ihre Bahnhof Uhr sehen lesen 00.00 ein wenig vorDie Sonne steht über ihnen. Die Uhren in Städten am östlichen Rand der Region zeigen kurz nach Sonnenaufgang 12:00 Uhr an .

Politiker auf der ganzen Welt zeigten eine Vorliebe dafür, die Offset (s) ihrer Gerichtsbarkeit zu ändern. Die Gründe variieren, wie Diplomatie, Krieg und Besatzung und die Albernheit der Sommerzeit (DST) . Die Gründe variieren, aber ihre Änderungen kommen mit überraschender Häufigkeit. Eine Zeitzone ist ein Name, der einer Region gegeben wird, um den Verlauf solcher Änderungen zu verfolgen. Ein Versatz von UTC ist also nur eine Anzahl von Stunden-Minuten-Sekunden vor oder hinter dem Nullmeridian. Eine Zeitzone ist viel mehr: eine Geschichte vergangener, gegenwärtiger und zukünftiger Veränderungen der Offsets einer bestimmten Region. Während zwei benachbarte Regionen heute möglicherweise denselben Offset von UTC haben, können sie sich in der Vergangenheit oder Zukunft je nach den unterschiedlichen Launen oder der Logik ihrer Politiker unterscheiden.

Dies bedeutet, dass die von Politikern definierte moderne Zeiterfassung wenig mit der Geographie zu tun hat. Zum Beispiel hat das riesige Land Indien heute eine einzige Zeitzone (Offset von UTC von +05: 30). So ist der Sonnenmittag (Sonne direkt über Ihrem Kopf) an verschiedenen Orten auf dem riesigen Subkontinent Stunden voneinander entfernt. Die indischen Politiker beschlossen dies, um zur Vereinheitlichung ihrer vielfältigen Demokratie beizutragen. In anderen Beispielen auf der ganzen Welt sehen wir, dass Regionen ihre Zeitzone als Symbol für internationale Beziehungen verwenden, z. B. um sich von ihrem beleidigenden Nachbarland zu unterscheiden, oder dass sie dieselbe Zone als Nachbar wählen, wenn die Beziehungen auftauen, wie sich kürzlich in Nordkorea geändert hat Südkorea. Heutzutage ist die Sonnenzeit nur eine von mehreren Überlegungen bei der Zeiterfassung.


Ü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.

Weitere Informationen finden Sie im Oracle-Lernprogramm . Suchen Sie im Stapelüberlauf nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310 .

Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu den Klassen java.time .

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. Hibernate 5 und JPA 2.2 unterstützen java.time .

Woher bekomme ich die java.time-Klassen?

Tabelle, welche java.time-Bibliothek mit welcher Java- oder Android-Version verwendet werden soll

Basil Bourque
quelle
Sie meinen, der Wert des Versatzes ist zu verschiedenen Zeiten in einer Zone unterschiedlich? vielen Dank!
FredSuvn
1
@FredSuvn Das ist genau die Definition der Sommerzeit (DST), das halbe Jahr ein Versatz und das halbe Jahr ein anderes. Und die Sommerzeit ist nicht die einzige Ursache. Andere Anomalien verursachen Änderungen des Versatzes für bestimmte Zeitzonen. Beispielsweise hat die Türkei im Herbst 2016 beschlossen, ihren Versatz eine Stunde vor UTC dauerhaft anzupassen ( +03:00). Politiker nehmen solche Änderungen häufig vor, oft ohne Vorankündigung. Dies führt dazu, dass die Benutzer sich bemühen, die 'tzdata'-Datenbankliste ihrer Computer mit den Zonendefinitionen zu aktualisieren.
Basil Bourque
1
Beste Antwort, die ich seit einiger Zeit auf SO gesehen habe 😀 @FredSuvn Sie sollten die Antwort akzeptieren, indem Sie auf die ✅
earcam
Für alle anderen, die durch die Gleichung Zeitzone = (Verlauf von Offsets + Regeln für Anomalien) verwirrt sind . Dies bedeutet nicht , dass Sie bei der Verwendung zone.getRules().getOffset(instant)zusätzliche Anomalien zum erfassten Versatz manuell hinzufügen müssen, z. B. die Sommerzeit. Der von zurückgegebene Offset getOffset(instant)ist bereits die genaue Anzahl von Stunden, Minuten und Sekunden, die zu diesem Zeitpunkt von GMT versetzt wurden. (Ich dachte immer, der Versatz sei nur der geografische Versatz, der beschreibt, wie viel früher / später die Sonne in dieser Region aufgeht, aber er berücksichtigt tatsächlich alle Regeln.)
anddero
@anddero Ihr Kommentar hat mich dazu inspiriert, diese Gleichung zu löschen und einen Abschnitt über Sonnenzeit und politische Zeit hinzuzufügen. Hoffentlich liest sich das jetzt klarer.
Basil Bourque
0

Abhängig von Ihrem Ziel können Sie möglicherweise vollständig umgehenZoneOffset .

Angenommen, Sie benötigen nur eine ZoneOffsetfür z. B. LocalDateTime.ofEpochSecond()können Sie ersetzen

ZoneOffset offset = OffsetDateTime.now().getOffset();
LocalDateTime dt1 = LocalDateTime.ofEpochSecond(seconds, 0, offset);

mit

LocalDateTime dt2 = LocalDateTime.ofInstant(
    Instant.ofEpochSecond(seconds), 
    ZoneId.systemDefault());

wo dt1.equals(dt2)ist true.

Cavok
quelle