Mengapa ZoneOffset.UTC! = ZoneId.of ("UTC")?

125

Kenapa

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

mencetak false?

Saya berharap kedua ZonedDateTimecontoh sama.

Johannes Flügel
sumber

Jawaban:

180

Jawabannya berasal dari javadocZoneId (penekanan saya) ...

ZoneId digunakan untuk mengidentifikasi aturan yang digunakan untuk mengonversi antara Instan dan LocalDateTime. Ada dua jenis ID yang berbeda:

  • Offset tetap - offset yang diselesaikan sepenuhnya dari UTC / Greenwich, yang menggunakan offset yang sama untuk semua tanggal-waktu lokal
  • Kawasan geografis - area di mana sekumpulan aturan khusus untuk menemukan pengimbangan dari UTC / Greenwich berlaku

Sebagian besar offset tetap diwakili oleh ZoneOffset. Memanggil normalized () pada ZoneId mana pun akan memastikan bahwa ID offset tetap akan direpresentasikan sebagai ZoneOffset.

... dan dari javadocZoneId#of (penekanan saya):

Metode ini mem-parsing ID yang menghasilkan ZoneId atau ZoneOffset. ZoneOffset dikembalikan jika ID-nya adalah 'Z', atau dimulai dengan '+' atau '-' .

Id argumen ditentukan sebagai "UTC", oleh karena itu ia akan mengembalikan ZoneIddengan offset, yang juga disajikan dalam bentuk string:

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

Keluaran:

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

Saat Anda menggunakan equalsmetode untuk perbandingan, Anda memeriksa kesetaraan objek . Karena perbedaan yang dijelaskan, hasil evaluasi adalah false.

Ketika normalized()metode digunakan seperti yang diusulkan dalam dokumentasi, perbandingan menggunakan equalsakan kembali true, seperti yang normalized()akan mengembalikan ZoneOffset:

Menormalkan ID zona waktu, mengembalikan ZoneOffset jika memungkinkan.

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

Seperti yang dinyatakan dalam dokumentasi, jika Anda menggunakan "Z"atau "+0"sebagai input id, ofakan mengembalikan ZoneOffsetsecara langsung dan tidak perlu memanggil normalized():

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

Untuk memeriksa apakah mereka menyimpan waktu tanggal yang sama , Anda dapat menggunakan isEqualmetode ini sebagai gantinya:

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

Sampel

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

Keluaran:

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
sumber
4
Dokumen tersebut juga mengatakan "Jika ID zona sama dengan 'GMT', 'UTC' atau 'UT' maka hasilnya adalah ZoneId dengan ID yang sama dan aturan yang setara dengan ZoneOffset.UTC". ID dan aturan yang sama, tetapi perilaku yang berbeda. ZoneId.of("Z")memberi Anda ZoneOffset.UTCtetapi ZoneId.of("UTC")memberi Anda ZoneId(yang tidak ZoneOffset.UTC). API ini tidak intuitif, untuk sedikitnya.
Adam Millerchip