Pourquoi ZoneOffset.UTC! = ZoneId.of («UTC»)?

125

Pourquoi

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

imprimer false?

Je m'attendrais à ce que les deux ZonedDateTimeinstances soient égales.

Johannes Flügel
la source

Réponses:

180

La réponse vient du javadoc deZoneId (c'est moi qui souligne) ...

Un ZoneId est utilisé pour identifier les règles utilisées pour convertir entre un Instant et un LocalDateTime. Il existe deux types d'identifiants distincts:

  • Décalages fixes - un décalage entièrement résolu par rapport à UTC / Greenwich, qui utilise le même décalage pour toutes les dates-heures locales
  • Régions géographiques - une zone où un ensemble spécifique de règles pour trouver le décalage par rapport à UTC / Greenwich s'applique

La plupart des décalages fixes sont représentés par ZoneOffset. L'appel de normalized () sur n'importe quel ZoneId garantira qu'un ID de décalage fixe sera représenté comme un ZoneOffset.

... et du javadoc deZoneId#of (c'est moi qui souligne):

Cette méthode analyse l'ID produisant un ZoneId ou ZoneOffset. Un ZoneOffset est renvoyé si l'ID est «Z» ou commence par «+» ou «-» .

L'argument id est spécifié comme "UTC", donc il retournera a ZoneIdavec un offset, qui est également présenté sous forme de chaîne:

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

Les sorties:

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

Lorsque vous utilisez la equalsméthode de comparaison, vous vérifiez l'équivalence des objets . En raison de la différence décrite, le résultat de l'évaluation est false.

Lorsque la normalized()méthode est utilisée telle que proposée dans la documentation, la comparaison avec equalsretournera true, ainsi que normalized()le correspondant ZoneOffset:

Normalise l'ID de fuseau horaire, renvoyant un ZoneOffset dans la mesure du possible.

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

Comme l'indique la documentation, si vous utilisez "Z"ou "+0"comme identifiant d'entrée, ofretournera le ZoneOffsetdirectement et il n'est pas nécessaire d'appeler normalized():

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

Pour vérifier s'ils stockent la même date et heure , vous pouvez utiliser la isEqualméthode à la place:

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

Échantillon

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"))));

Production:

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
DVarga
la source
4
La documentation dit également "Si l'ID de zone est égal à" GMT "," UTC "ou" UT ", le résultat est un ZoneId avec le même ID et des règles équivalentes à ZoneOffset.UTC". Même identifiant et règles, mais comportement différent. ZoneId.of("Z")vous donne ZoneOffset.UTCmais vous ZoneId.of("UTC")donne un ZoneId(ce qui n'est pas ZoneOffset.UTC). Cette API est pour le moins peu intuitive.
Adam Millerchip