4

競合するゾーン ID とオフセットを持つ文字列を解析するときに、予想される動作が何であるかを見つけることができませんでした。

例えば:

ZonedDateTime d = ZonedDateTime.parse("2015-06-17T12:55:33+05:00[Europe/Amsterdam]");
println(d.toString()); // prints 2015-06-17T12:55:33+02:00[Europe/Amsterdam]

この場合parse()、 の誤ったオフセットを無視+05:00し、ゾーン ID ( Europe/Amsterdam)によって決定されるオフセットを使用するようです。

ドキュメントが言うように:

どのオフセットが有効かはゾーンによって制御されるため、オフセットを自由に設定することはできません。

は zone の無効なオフセットであるparse()ため、例外がスローされると予想していました。この場合の正しい動作は何ですか?+05:00Europe/Amsterdam

4

1 に答える 1

4

解析は暗黙的に の static メソッドfrom(TemporalAccessor)を呼び出しますZonedDateTime。そのドキュメントには次のように記載されています。

変換では、最初に時間オブジェクトから ZoneId を取得し、必要に応じて ZoneOffset にフォールバックします。

これは、ゾーン ID がオフセット情報と比較して優先されるという観測をサポートします。厳密モードを明示的に使用する場合、私は-あなたと同じように-例外を期待します:

DateTimeFormatter dtf = 
  new DateTimeFormatterBuilder()
  .parseStrict()
  .appendPattern("uuuu-MM-dd'T'HH:mm:ssXXX'['VV']'").toFormatter();
ZonedDateTime d = ZonedDateTime.parse("2015-06-17T12:55:33+05:00[Europe/Amsterdam]", dtf);
System.out.println(d.toString()); // 2015-06-17T12:55:33+02:00[Europe/Amsterdam]

ただし、例外は見られません。また、メソッドはISO_ZONED_DATE_TIMEparse(String)を使用するように文書化されています (同じ結果で私もテストしました)。これも厳密に定義されています。おそらく、Oracleに問題を提出できます。何を「正しい動作」と見なすか、つまり、この動作を文書化されていない機能またはバグと見なすかどうかを決定するのは、彼ら次第です。

個人的には、これはバグだと考えています。たとえば、LocalDate.parse("Friday, 2016-03-08", new DateTimeFormatterBuilder().parseLenient().appendPattern("EEEE, uuuu-MM-dd").toFormatter().withLocale(Locale.ENGLISH))あいまいな (平日の) 情報のために式が実際に例外を生成するためです。


比較のために: 私の時間ライブラリ Time4J では、オフセット情報が一貫しているかどうかのチェックを実装しました。

ChronoFormatter<Moment> cf = 
    ChronoFormatter.ofMomentPattern("uuuu-MM-dd'T'HH:mm:ssXXX'['VV']'", PatternType.CLDR, Locale.ROOT, ZonalOffset.UTC);
System.out.println(cf.with(Leniency.STRICT).parse("2015-06-17T12:55:33+05:00[Europe/Amsterdam]"));
// Exception in thread "main" java.text.ParseException: Ambivalent offset information: AMSTERDAM versus +05:00

// this alternative formatter can be used as workaround for strict parsing
ZonedDateTime zdt = 
  ZonalDateTime.parse(
    "2015-06-17T12:55:33+05:00[Europe/Amsterdam]", 
    cf.with(Leniency.STRICT)
  ).toTemporalAccessor();
于 2016-03-08T13:12:00.040 に答える