Gibt es eine Möglichkeit, ZoneId in Java 8 in ZoneOffset zu konvertieren?

85

Ich habe eine Epochensekunde und eine zoneId nach Methode1. Es kann mit der Systemstandardzone zoneId in LocalDateTime konvertiert werden, aber ich finde keine Möglichkeit, die Epochensekunde nach Methode2 in LocalDateTime zu konvertieren, da es keine gibt. ZoneOffset.systemDefaultIch denke, es ist dunkel.

import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset}

val epochSecond = System.currentTimeMillis() / 1000

LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), ZoneId.systemDefault())//method1
LocalDateTime.ofEpochSecond(epochSecond, 0, ZoneOffset.MAX)//method2
Renkai
quelle
Welche Sprache / welchen Dialekt verwenden Sie, damit der Massenimport import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset}funktioniert? Es ist ein unexpected tokenfür mich in Java 11.
anddero
1
Kann Scala sein, aber das ist hier nicht wirklich wichtig
Donatas M
1
Ich habe die Theorie dahinter java.timehier ausführlich
Ondra Žižka

Antworten:

109

Hier ist , wie Sie bekommen können ZoneOffsetaus ZoneId:

Instant instant = Instant.now(); //can be LocalDateTime
ZoneId systemZone = ZoneId.systemDefault(); // my timezone
ZoneOffset currentOffsetForMyZone = systemZone.getRules().getOffset(instant);

Hinweis: ZoneIdJe nach Zeitpunkt und Verlauf des jeweiligen Ortes kann der Versatz unterschiedlich sein. Die Auswahl verschiedener Instanzen würde also zu unterschiedlichen Offsets führen.

NB2: ZoneId.of()kann ein zurückgeben, ZoneOffsetanstatt ZoneIdwenn UTC+3/ GMT+2/ etc im Gegensatz zu einer Zeitzone wie übergeben wird Africa/Cairo. Wenn also UTC / GMT-Offsets übergeben werden, werden historische / geografische / Sommerzeitinformationen des Instantnicht berücksichtigt - Sie arbeiten einfach mit dem angegebenen Offset.

Stanislav Bashkyrtsev
quelle
Dies ergibt einen falschen Wert, wenn sich der aktuelle Zeitpunkt in der Sommerzeit befindet, aber zum Zeitpunkt der Berechnung war es ohne Sommerzeit
msangel
@msangel, kannst du das überprüfen? Vielleicht verwenden Sie ZoneId.systemDefault()Ihren Code und er gibt auf verschiedenen Computern unterschiedliche Zeitzonen zurück?
Stanislav Bashkyrtsev
Ich habe das überprüft und es funktioniert abhängig von einer anderen Bedingung. Aktualisierte Antwort damit.
Msangel
43

Es gibt keine Eins-zu-Eins-Zuordnung. Eine ZoneId definiert eine geografische Ausdehnung, in der im Laufe der Zeit eine Reihe verschiedener ZoneOffsets verwendet wird. Wenn die Zeitzone Sommerzeit verwendet, unterscheidet sich das ZoneOffset zwischen Sommer und Winter.

Darüber hinaus haben sich die Sommerzeitregeln möglicherweise im Laufe der Zeit geändert, sodass sich das ZoneOffset beispielsweise für den 13.10.2015 vom 13.10.1980 unterscheiden kann.

Sie können das ZoneOffset für eine ZoneId also nur für einen bestimmten Instant finden.

Siehe auch https://en.wikipedia.org/wiki/Tz_database

GreyFairer
quelle
10
Ich weiß das, aber wie wird es gemacht? Wenn ich das LocaDate kenne und eine ZoneId habe, wie konvertiere ich es in ein ZoneOffset. Mein Anwendungsfall ist eine Zeichenfolge, die eine Zeit und eine Zone enthält. Ich möchte die Zeichenfolge in eine OffsetTime analysieren, ohne die Zoneninformationen zu löschen.
Kai Moritz
31

tl; dr

ZonedDateTime.now( 
    ZoneId.of( "America/Montreal" ) 
)

… Der aktuellen Standardzeitzone…

ZonedDateTime.now( 
    ZoneId.systemDefault() 
)

Einzelheiten

Die Antwort von Stanislav Bshkyrtsev beantwortet Ihre Frage richtig und direkt.

Es gibt jedoch größere Probleme, wie in der Antwort von Jon Skeet vorgeschlagen .

LocalDateTime

Ich finde keine Möglichkeit, die zweite Epoche in LocalDateTime umzuwandeln

LocalDateTimehat absichtlich kein Konzept der Zeitzone oder des Versatzes von UTC. Nicht wahrscheinlich, was Sie wollen. Das Local…bedeutet jeden Ort, keinen bestimmten Ort. Diese Klasse repräsentiert keinen Moment, sondern nur potenzielle Momente in einem Bereich von etwa 26 bis 27 Stunden (dem Bereich der Zeitzonen rund um den Globus).

Instant

Sie müssen nicht mit Sekunden beginnen, wenn Sie versuchen, die aktuelle Zeit abzurufen. Holen Sie sich den aktuellen 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).

Instant instant = Instant.now();

Darin Instantbefindet sich eine Anzahl von Nanosekunden aus der Epoche. Aber das interessiert uns nicht wirklich.

ZonedDateTime

Wenn Sie diesen Moment durch die Linse der Wanduhrzeit einer bestimmten Region sehen möchten, wenden Sie a ZoneIdan , um a zu erhalten ZonedDateTime.

ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdt = instant.atZone( z );

Als Abkürzung können Sie direkt auf die ZonedDateTime.

ZonedDateTime zdt = ZonedDateTime.now( z );  

A ZonedDateTimehat ein Instantin sich. Rufen Sie zdt.toInstant()an, um den gleichen Zeitpunkt wie einen Grundwert in UTC zu erhalten . Gleiche Anzahl von Nanosekunden seit der Epoche, entweder als ZonedDateTimeoder als Instant.

Sekunden seit der Epoche gegeben

Wenn Sie eine Anzahl von Sekunden seit der Epoche erhalten und die Epoche der erste Moment von 1970 in UTC ( 1970-01-01T00:00:00Z) ist, geben Sie diese Zahl an ein Instant.

long secondsSinceEpoch = 1_484_063_246L ;
Instant instant = Instant.ofEpochSecond( secondsSinceEpoch ) ;

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


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

Basil Bourque
quelle
10

In der Dokumentation heißt es: "Dies ist in erster Linie für Konvertierungen auf niedriger Ebene und nicht für die allgemeine Verwendung von Anwendungen gedacht."

Das Durchgehen Instantmacht für mich vollkommen Sinn - Ihre Epochensekunde ist effektiv eine andere Darstellung von a. InstantKonvertieren Sie also in eine Instantund konvertieren Sie diese dann in eine bestimmte Zeitzone.

Jon Skeet
quelle
9

Ich hoffe, die ersten beiden Zeilen meiner Lösung unten sind hilfreich. Mein Problem war, dass ich eine LocalDateTimeund den Namen einer Zeitzone hatte, und ich brauchte eine, instantdamit ich eine erstellen konnte java.util.Date, denn genau das wollte MongoDB. Mein Code ist Scala, aber hier ist er so nah an Java, dass ich denke, es sollte kein Problem geben, ihn zu verstehen:

val zid = ZoneId.of(tzName)                                // "America/Los_Angeles"
val zo: ZoneOffset = zid.getRules.getOffset(localDateTime) // ⇒ -07:00
                                         // 2017-03-16T18:03

val odt = OffsetDateTime.of(localDateTime, zo) // ⇒ 2017-03-16T18:03:00-07:00
val instant = odt.toInstant                    // ⇒ 2017-03-17T01:03:00Z
val issued = Date.from(instant)
gknauth
quelle
1
Ich habe diese Antwort hier gepostet, weil dies die Seite war, die auftauchte, als ich nach einer Möglichkeit suchte, das zu tun, was ich schließlich herausgefunden hatte.
Gknauth
1

Im Folgenden wird die Zeit in Millisekunden zurückgegeben, die zur UTC hinzugefügt werden muss, um die Standardzeit in dieser Zeitzone zu erhalten:

TimeZone.getTimeZone(ZoneId.of("Europe/Amsterdam")).getRawOffset()
Jelmer
quelle
0

Ich habe eine zweite Epoche und eine ZoneId. Gibt es eine Möglichkeit, ZoneId in Java 8 in ZoneOffset zu konvertieren?

  1. Holen Sie sich ZonedDateTimeaus der zweiten Epoche und Zone Id
  2. Holen Sie sich ZoneOffsetvonZonedDateTime

Demo:

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        // Get ZonedDateTime from epoch second and Zone Id
        ZonedDateTime zdt = Instant.ofEpochSecond(1597615462L).atZone(ZoneId.of("Europe/London"));

        // Get ZoneOffset from ZonedDateTime
        ZoneOffset offset = zdt.getOffset();

        System.out.println(offset);
    }
}

Ausgabe:

+01:00
Arvind Kumar Avinash
quelle