Чому ZoneOffset.UTC! = ZoneId.of ("UTC")?


125

Чому

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

роздрукувати false?

Я б очікував, що обидва ZonedDateTimeвипадки будуть рівними.

Відповіді:


180

Відповідь походить від javadocZoneId (моє наголос) ...

ZoneId використовується для ідентифікації правил, які використовуються для перетворення між Instant і LocalDateTime. Існує два різних типи ідентифікатора:

  • Фіксований зсув - повністю вирішений зсув від UTC / Грінвіч, який використовує однакове зміщення для всіх місцевих дат
  • Географічні регіони - область, де застосовується специфічний набір правил для знаходження зрушення від UTC / Грінвіч

Більшість фіксованих компенсацій представлені ZoneOffset. Виклик нормалізований () на будь-якому ZoneId забезпечить, що фіксований ідентифікатор зміщення буде представлений як ZoneOffset.

... і від javadocZoneId#of (наголос міни):

Цей метод аналізує ідентифікатор, створюючи ZoneId або ZoneOffset. Зона повернення повертається, якщо ідентифікатор "Z", або починається з "+" або "-" .

Ідентифікатор аргументу вказаний як "UTC", тому він поверне a ZoneIdзі зміщенням, яке також представлено у рядковій формі:

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

Виходи:

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

Використовуючи equalsметод для порівняння, ви перевіряєте на предмет еквівалентність . Через описану різницю результат оцінки є false.

Коли normalized()метод використовується, як запропоновано в документації, порівняння з використанням equalsповернеться true, як normalized()і поверне відповідне ZoneOffset:

Нормалізує ідентифікатор часового поясу, повертаючи ZoneOffset, де це можливо.

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

Як зазначено в документації, якщо ви використовуєте "Z"або "+0"як вхідний ідентифікатор, ofбуде повернено ZoneOffsetбезпосередньо, і не потрібно телефонувати normalized():

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

Щоб перевірити, чи зберігають вони один і той же час , ви можете скористатися isEqualметодом:

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

Зразок

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

Вихід:

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
Документи також кажуть "Якщо ідентифікатор зони дорівнює" GMT "," UTC "або" UT ", то результат - ZoneId з тим же ідентифікатором і правилами, що еквівалентні ZoneOffset.UTC". Той самий ідентифікатор і правила, але різні поведінки. ZoneId.of("Z")дає вам, ZoneOffset.UTCале ZoneId.of("UTC")дає вам ZoneId(це не так ZoneOffset.UTC). Цей API не менш інтуїтивно зрозумілий.
Адам Міллерчіп
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.