Warum ist ZoneOffset.UTC! = ZoneId.of ("UTC")?


124

Warum tut

ZonedDateTime now = ZonedDateTime.now();
System.out.println(now.withZoneSameInstant(ZoneOffset.UTC)
        .equals(now.withZoneSameInstant(ZoneId.of("UTC"))));

ausdrucken false?

Ich würde erwarten, dass beide ZonedDateTimeInstanzen gleich sind.

Antworten:


179

Die Antwort kommt aus dem Javadoc vonZoneId (Hervorhebung von mir) ...

Eine ZoneId wird verwendet, um die Regeln zu identifizieren, die zum Konvertieren zwischen einem Instant und einem LocalDateTime verwendet werden. Es gibt zwei verschiedene Arten von IDs:

  • Feste Offsets - ein vollständig aufgelöster Offset von UTC / Greenwich, der für alle lokalen Datums- und Uhrzeitangaben denselben Offset verwendet
  • Geografische Regionen - Ein Gebiet, in dem bestimmte Regeln für die Ermittlung des Versatzes von UTC / Greenwich gelten

Die meisten festen Offsets werden durch ZoneOffset dargestellt. Durch Aufrufen von normalized () auf einer beliebigen ZoneId wird sichergestellt, dass eine feste Offset-ID als ZoneOffset dargestellt wird.

... und aus dem Javadoc vonZoneId#of (Schwerpunkt Mine):

Diese Methode analysiert die ID und erzeugt eine ZoneId oder ZoneOffset. Ein ZoneOffset wird zurückgegeben, wenn die ID 'Z' lautet oder mit '+' oder '-' beginnt .

Die Argument-ID wird als angegeben "UTC", daher wird a ZoneIdmit einem Offset zurückgegeben, der auch in der Zeichenfolgenform dargestellt wird:

System.out.println(now.withZoneSameInstant(ZoneOffset.UTC));
System.out.println(now.withZoneSameInstant(ZoneId.of("UTC")));

Ausgänge:

2017-03-10T08:06:28.045Z
2017-03-10T08:06:28.045Z[UTC]

Wenn Sie die equalsVergleichsmethode verwenden, überprüfen Sie die Objektäquivalenz . Aufgrund des beschriebenen Unterschieds ist das Ergebnis der Bewertungfalse .

Wenn die normalized()in der Dokumentation vorgeschlagene Methode verwendet wird, wird der Vergleich mit equalszurückgegeben true, und es normalized()wird Folgendes zurückgegeben ZoneOffset:

Normalisiert die Zeitzonen-ID und gibt nach Möglichkeit ein ZoneOffset zurück.

now.withZoneSameInstant(ZoneOffset.UTC)
    .equals(now.withZoneSameInstant(ZoneId.of("UTC").normalized())); // true

Wie in der Dokumentation angegeben, wird bei Verwendung von "Z"oder "+0"als Eingabe-ID ofdie ZoneOffsetdirekt zurückgegeben, und es besteht keine Notwendigkeit, Folgendes aufzurufen normalized():

now.withZoneSameInstant(ZoneOffset.UTC).equals(now.withZoneSameInstant(ZoneId.of("Z"))); //true
now.withZoneSameInstant(ZoneOffset.UTC).equals(now.withZoneSameInstant(ZoneId.of("+0"))); //true

Um zu überprüfen, ob sie das gleiche Datum und die gleiche Uhrzeit speichern , können Sie isEqualstattdessen die folgende Methode verwenden:

now.withZoneSameInstant(ZoneOffset.UTC)
    .isEqual(now.withZoneSameInstant(ZoneId.of("UTC"))); // true

Stichprobe

System.out.println("equals - ZoneId.of(\"UTC\"): " + nowZoneOffset
        .equals(now.withZoneSameInstant(ZoneId.of("UTC"))));
System.out.println("equals - ZoneId.of(\"UTC\").normalized(): " + nowZoneOffset
        .equals(now.withZoneSameInstant(ZoneId.of("UTC").normalized())));
System.out.println("equals - ZoneId.of(\"Z\"): " + nowZoneOffset
        .equals(now.withZoneSameInstant(ZoneId.of("Z"))));
System.out.println("equals - ZoneId.of(\"+0\"): " + nowZoneOffset
        .equals(now.withZoneSameInstant(ZoneId.of("+0"))));
System.out.println("isEqual - ZoneId.of(\"UTC\"): "+ nowZoneOffset
        .isEqual(now.withZoneSameInstant(ZoneId.of("UTC"))));

Ausgabe:

equals - ZoneId.of("UTC"): false
equals - ZoneId.of("UTC").normalized(): true
equals - ZoneId.of("Z"): true
equals - ZoneId.of("+0"): true
isEqual - ZoneId.of("UTC"): true

4
In den Dokumenten heißt es außerdem: "Wenn die Zonen-ID gleich 'GMT', 'UTC' oder 'UT' ist, ist das Ergebnis eine ZoneId mit derselben ID und denselben Regeln wie ZoneOffset.UTC." Gleiche ID und Regeln, aber unterschiedliches Verhalten. ZoneId.of("Z")gibt dir ZoneOffset.UTCaber ZoneId.of("UTC")gibt dir ein ZoneId(das ist nicht ZoneOffset.UTC). Diese API ist, gelinde gesagt, nicht intuitiv.
Adam Millerchip
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.