だから私はこのコードが新しいJava 8 date/timeパッケージの下で動作することを期待しています):
ZonedDateTime now = ZonedDateTime.now();
System.out.println(ZonedDateTime.parse(
now.format(DateTimeFormatter.ISO_INSTANT),
DateTimeFormatter.ISO_INSTANT));
しかし、明らかにそうではありません:
Exception in thread "main" Java.time.format.DateTimeParseException: Text '2014-09-01T19:37:48.549Z' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {MilliOfSecond=549, NanoOfSecond=549000000, MicroOfSecond=549000, InstantSeconds=1409600268},ISO of type Java.time.format.Parsed
at Java.time.format.DateTimeFormatter.createError(DateTimeFormatter.Java:1918)
at Java.time.format.DateTimeFormatter.parse(DateTimeFormatter.Java:1853)
at Java.time.ZonedDateTime.parse(ZonedDateTime.Java:597)
私はすでにこのエントリを見ましたが、ローカルのものではなくZonedDateTimeオブジェクトが必要であり、8u20がすでにインストールされているため、助けにはなりませんでした: DateTimeFormatterとZonedDateTime in Java 8
ここで何が起こっているのか誰にも分かりますか?
_ISO_INSTANT
_フォーマッターは文書化されています ここ -「これは、インスタントの人間が読める形式を許可することを目的とした特別な場合のフォーマッターです」。そのため、このフォーマッタはInstant
ではなくZonedDateTime
で使用することを目的としています。
フォーマット時に、_ISO_INSTANT
_は、_ChronoField.INSTANT_SECONDS
_および_ChronoField.NANO_OF_SECOND
_を提供できる一時オブジェクトをフォーマットできます。 Instant
とZonedDateTime
の両方がこれらの2つのフィールドを提供できるため、両方とも機能します。
_// works with Instant
Instant instant = Instant.now();
System.out.println(DateTimeFormatter.ISO_INSTANT.format(instant));
// works with ZonedDateTime
ZonedDateTime zdt = ZonedDateTime.now();
System.out.println(zdt.format(DateTimeFormatter.ISO_INSTANT));
// example output
2014-09-02T08:05:23.653Z
_
解析するとき、_ISO_INSTANT
_は_ChronoField.INSTANT_SECONDS
_と_ChronoField.NANO_OF_SECOND
_のみを生成します。 Instant
はこれらの2つのフィールドから作成できますが、ZonedDateTime
にはZoneId
も必要です。
ZonedDateTime
を解析するには、タイムゾーンZoneId
が存在することが不可欠です。タイムゾーンは、(a)文字列から解析するか、(b)フォーマッタに指定できます(JDK 8u20を使用):
_// option a - parsed from the string
DateTimeFormatter f = DateTimeFormatter.ISO_DATE_TIME;
ZonedDateTime zdt = ZonedDateTime.parse("2014-09-02T08:05:23.653Z", f);
// option b - specified in the formatter - REQUIRES JDK 8u20 !!!
DateTimeFormatter f = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.systemDefault());
ZonedDateTime zdt = ZonedDateTime.parse("2014-09-02T08:05:23.653Z", f);
_
_ISO_ZONED_DATE_TIME
_ 、 _ISO_OFFSET_DATE_TIME
_ 、および _ISO_DATE_TIME
_ のドキュメントを参照してくださいwithZone()
)を指定せずにZonedDateTime
を解析します。
_ISO_INSTANT
_フォーマッターは、Instant
で動作するように設計された特別な場合のフォーマッターです。 ZonedDateTime
を使用している場合は、_ISO_DATE_TIME
_や_ISO_ZONED_DATE_TIME
_などの別のフォーマッターを使用する必要があります。
わからないが、これはJava 8.のバグかもしれないデフォルトの動作になります(ZoneIdが指定されていない場合は、システムのデフォルトを使用します)。
ZonedDateTime now = ZonedDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT
.withZone(ZoneId.systemDefault());
System.out
.println(ZonedDateTime.parse(now.format(formatter), formatter));
OpenJDKで修正された同様のバグがあります: JDK-8033662 -しかしそれは似ているだけで、まったく同じではありません。
それが予想される動作であるかどうかはわかりませんが(おそらくそうです)、技術的にはISO_INSTANT
フォーマッタにはタイムゾーンは含まれません。 DateTimeFormatter.ISO_ZONED_DATE_TIME
フォーマッタではなく、期待どおりの結果が得られます。