Por que ZoneOffset.UTC! = ZoneId.of ("UTC")?

125

Porque

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

imprimir false?

Eu esperaria que as duas ZonedDateTimeinstâncias fossem iguais.

Johannes Flügel
fonte

Respostas:

180

A resposta vem do javadoc deZoneId (ênfase minha) ...

Um ZoneId é usado para identificar as regras usadas para converter entre um Instant e um LocalDateTime. Existem dois tipos distintos de ID:

  • Compensações fixas - uma compensação totalmente resolvida do UTC / Greenwich, que usa a mesma compensação para todas as datas e horários locais
  • Regiões geográficas - uma área em que se aplica um conjunto específico de regras para encontrar a compensação do UTC / Greenwich

A maioria das compensações fixas é representada pelo ZoneOffset. Chamar normalizado () em qualquer ZoneId garantirá que um ID de deslocamento fixo seja representado como um ZoneOffset.

... e do javadoc deZoneId#of (ênfase minha):

Este método analisa o ID que produz um ZoneId ou ZoneOffset. Um ZoneOffset será retornado se o ID for 'Z' ou iniciar com '+' ou '-' .

O ID do argumento é especificado como "UTC", portanto, ele retornará a ZoneIdcom um deslocamento, que também é apresentado no formato string:

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

Saídas:

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

Ao usar o equalsmétodo de comparação, você verifica a equivalência do objeto . Devido à diferença descrita, o resultado da avaliação é false.

Quando o normalized()método é usado conforme proposto na documentação, a comparação usando equalsretornará true, assim como normalized()retornará o correspondente ZoneOffset:

Normaliza o ID do fuso horário, retornando um ZoneOffset sempre que possível.

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

Como a documentação declara, se você usar "Z"ou "+0"como ID de entrada, ofretornará o ZoneOffsetdiretamente e não será necessário chamar normalized():

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

Para verificar se eles armazenam a mesma data e hora , você pode usar o isEqualmétodo:

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

Amostra

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

Resultado:

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
fonte
4
Os documentos também dizem "Se o ID da zona for igual a 'GMT', 'UTC' ou 'UT', o resultado será um ZoneId com o mesmo ID e regras equivalentes a ZoneOffset.UTC". Mesmo ID e regras, mas comportamento diferente. ZoneId.of("Z")dá a você, ZoneOffset.UTCmas ZoneId.of("UTC")dá a você ZoneId(isso não é ZoneOffset.UTC). Essa API não é intuitiva, para dizer o mínimo.
Adam Millerchip 06/03