it-swarm.dev

Kompatibilitas toTtring ZonedDateTime dengan ISO 8601

Saya mencoba memastikan bahwa memanggil toString() pada ZonedDateTime saya akan sesuai dengan format ISO-8601.

Dokumentasi untuk metode toString() menyatakan:

... Outputnya kompatibel dengan ISO-8601 jika offset dan ID adalah sama

Apakah ini berarti bahwa ada situasi di mana memanggil zdt.getOffset() Akan mengembalikan sesuatu yang berbeda dari zdt.getZone().getRules().getOffset(zdt.toInstant())?

Ini sepertinya tidak masuk akal.

Dapatkah seseorang memberikan contoh di mana offset dan ID tidak sama (yaitu: di mana toString() tidak mematuhi ISO-8601) sehingga saya dapat lebih memahami deskripsi dalam dokumentasi.

Terima kasih.

11
theyuv

Ini adalah spesifikasi lengkap:

 * Outputs this date-time as a {@code String}, such as
 * {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.
 * <p>
 * The format consists of the {@code LocalDateTime} followed by the {@code ZoneOffset}.
 * If the {@code ZoneId} is not the same as the offset, then the ID is output.
 * The output is compatible with ISO-8601 if the offset and ID are the same.

Spesifikasi Javadoc mengacu pada kasus di mana ZonedDateTime dibangun dengan ZoneOffset daripada nama ZoneId, sehingga offset dan IDnya sama:

System.out.println(ZonedDateTime.now(ZoneId.of("Europe/Paris")));
// 2017-04-26T15:13:12.006+02:00[Europe/Paris]

System.out.println(ZonedDateTime.now(ZoneOffset.ofHours(2)));
// 2017-04-26T15:13:12.016+02:00

Seperti dapat dilihat, dalam kasus kedua, di mana ZoneOffset digunakan, format toString() menghapus bagian braket persegi di bagian akhir. Dengan menghilangkan bagian itu, hasilnya kompatibel dengan ISO-8601.

boolean iso8601Compatible = zdt.getZone() instanceof ZoneOffset;

Untuk menjamin output yang kompatibel dengan ISO-8601 gunakan toOffsetDateTime():

String isoCompatible = zdt.toOffsetDateTime().toString();

atau formatter.

20
JodaStephen

Contoh di dokumentasi adalah 2007-12-03T10:15:30+01:00[Europe/Paris]. Ini tidak sesuai dengan ISO karena ISO-8601 tidak termasuk bagian [Europe/Paris]. Ini ditambahkan oleh pengembang Java.time dalam kompromi antara mendapatkan sedekat mungkin dengan standar dan tetap memberikan informasi zona waktu dengan cara yang tidak ambigu.

Jadi pertanyaan sebenarnya mungkin sebaliknya: jika ZonedDateTime.toString() menyertakan informasi zona waktu yang tidak dimasukkan oleh ISO, ketika is hasilnya sepenuhnya sesuai dengan ISO? Apa artinya “jika offset dan ID sama”? Di sini kita harus ingat bahwa ZoneOffset adalah subclass dari ZoneID dan dapat digunakan sebagai ID zona dalam ZonedDateTime. Dalam hal ini offset dan ID adalah sama. Kalau tidak, mereka tidak. Untuk contoh spesifik, ZonedDateTime.now(ZoneOffset.ofHours(+2)).toString() dapat menghasilkan 2017-04-26T15:04:59.828+02:00. Ini sepenuhnya kompatibel dengan ISO karena zona tersebut diberikan hanya +02:00, yang sama dengan offset. Juga ZonedDateTime.now(ZoneOffset.UTC).toString() memberikan sesuatu dalam format 2017-04-26T13:04:59.828Z. Karena Z dianggap sebagai offset, ini juga kompatibel.

Saya pikir dalam banyak kasus itu tidak akan sangat berguna. Jika zona Anda hanya offset, Anda biasanya lebih suka menggunakan OffsetDateTime daripada ZonedDateTime, dan jika demikian, tentu saja Anda tidak peduli apakah ZonedDateTime.toString() kompatibel dengan ISO atau tidak.

3
Ole V.V.

Saya suka di atas komentar terakhir JodaStephen 'atau formatter' , karena menggunakan formatter lebih kuat terlepas dari data . Alasannya adalah OffsetDateTime toString () lewati bagian unit kedua ketika tidak ada nilai pada unit kedua dan di bawah , jadi akhirnya memberikan yyyy-MM-ddTHH: mmZ bukannya yyyy-MM-ddTHH: mm: ssZ. Itu dapat menyebabkan masalah jika sistem lain mengharapkan format statis dan tidak memiliki kemampuan beradaptasi.

Di bawah ini adalah kode yang saya gunakan untuk mensimulasikan kedua kasus di mana tidak memiliki porsi waktu dan memilikinya.

/**
 * This function is design to convert Date object from other system to ISO dateTime String 
 * which will be sent to another system. and using formatter to lock up the format
 * @param date Java.util.Date
 * @return 'yyyy-MM-ddTHH:mm:ssZ' format ISO dateTime string
 */
public String formatIsoUtcDateTime(Date date) {
    if(null == date) {
        return null;
    }
    return ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("UTC"))
                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"));
}

// no time portion with using formatter
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Date date = sdf.parse("20171010");
System.out.println(formatIsoUtcDateTime(date));

// no time portion with using OffsetDateTime toString
System.out.println(ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("UTC")).toOffsetDateTime().toString());

// just current date and probably has at least millisecond, using formatter
System.out.println(formatIsoUtcDateTime(new Date()));

// just current date and probably has at least millisecond, using OffsetDateTime toString
// this will print yyyy-MM-ddTHH:mm:ss.SSSZ format
System.out.println(ZonedDateTime.ofInstant(new Date().toInstant(), ZoneId.of("UTC")).toOffsetDateTime().toString());
0
Steve Park

Sesuai dokumentasi resmi:

Mendapatkan offset untuk sesaat itu sederhana, karena ada tepat satu offset yang valid untuk setiap instan . Sebaliknya, memperoleh offset untuk waktu-tanggal lokal tidak mudah. Ada tiga kasus:

  • Normal, dengan satu offset yang valid. Untuk sebagian besar tahun, berlaku kasus normal, di mana ada offset yang valid untuk waktu-tanggal lokal.
  • Gap, dengan nol offset yang valid. Ini adalah ketika jam melompat maju biasanya karena perubahan tabungan siang hari musim semi dari "musim dingin" ke "musim panas". Di celah ada nilai-nilai tanggal-waktu lokal tanpa offset yang valid.
  • Tumpang tindih, dengan dua offset yang valid. Ini adalah ketika jam diatur kembali biasanya karena perubahan tabungan siang hari musim gugur dari "musim panas" ke "musim dingin". Dalam tumpang tindih ada nilai waktu tanggal lokal dengan dua offset yang valid.

Jadi kasus ke-2 dan ke-3 adalah situasi di mana toString () tidak akan sesuai dengan ISO-8601.

0
VivekRatanSinha