ZonedDateTime
オブジェクトのtoString()
の呼び出しがISO-8601形式に準拠することを保証しようとしています。
toString()
メソッドのドキュメントには次のように記載されています。
...オフセットとIDが同じ場合、出力はISO-8601と互換性があります
これは、zdt.getOffset()
を呼び出すとzdt.getZone().getRules().getOffset(zdt.toInstant())
とは異なるものが返される状況が存在することを意味しますか?
これは理にかなっていないようです。
誰かがオフセットとIDが同じではない例を提供できますか(つまり:toString()
がISO-8601に準拠していない場合)、ドキュメントの説明をよりよく理解できます。
ありがとうございました。
これは完全な仕様です:
_ * 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.
_
Javadoc仕様では、ZonedDateTime
が名前付きZoneOffset
ではなくZoneId
で構成されているため、オフセットとIDが同じ場合を参照しています。
_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
_
見てわかるように、ZoneOffset
が使用される2番目のケースでは、toString()
形式は最後の角括弧セクションを省略します。そのセクションを省略すると、結果はISO-8601互換になります。
_boolean iso8601Compatible = zdt.getZone() instanceof ZoneOffset;
_
ISO-8601互換の出力を保証するには、toOffsetDateTime()
を使用します。
_String isoCompatible = zdt.toOffsetDateTime().toString();
_
またはフォーマッター。
ドキュメント の例は_2007-12-03T10:15:30+01:00[Europe/Paris]
_です。 ISO-8601には_[Europe/Paris]
_部分が含まれていないため、これはISO準拠ではありません。これは_Java.time
_開発者によって、妥当な範囲で標準に近づくことと、明確な方法でタイムゾーン情報を提供することの間の妥協点で追加されました。
したがって、実際の質問は実際には反対かもしれません:ZonedDateTime.toString()
がISOに含まれないタイムゾーン情報を含む場合、is結果は完全にISOに準拠していますか? 「オフセットとIDが同じ場合」とはどういう意味ですか?ここで、ZoneOffset
はZoneID
のサブクラスであり、ZonedDateTime
のゾーンIDとして使用できることを覚えておく必要があります。この場合、オフセットとIDは同じです。そうでなければ、そうではありません。特定の例では、ZonedDateTime.now(ZoneOffset.ofHours(+2)).toString()
は_2017-04-26T15:04:59.828+02:00
_を生成する場合があります。ゾーンは_+02:00
_として指定されるため、これは完全にISO互換です。これはオフセットと同じです。また、ZonedDateTime.now(ZoneOffset.UTC).toString()
は、形式_2017-04-26T13:04:59.828Z
_で何かを提供します。 Z
はオフセットとしてカウントされるため、これも互換性があります。
ほとんどの場合、あまり有用ではないと思います。ゾーンが単なるオフセットの場合、通常はOffsetDateTime
よりもZonedDateTime
を使用することを好むでしょう。もしそうであれば、ZonedDateTime.toString()
がISO互換であるかどうかは気にしませんか否か。
私は、JodaStephenの最後のコメント'or formatter'が好きです。これは、データに関係なくフォーマッターを使用する方がより堅牢だからです。その理由は、OffsetDateTime toString()が2番目のユニット以下に値がないときに2番目のユニット部分をスキップするため、最終的にyyyy-MM-ddTHH:mmZyyyy-MM-ddTHH:mm:ssZの代わりに。他のシステムが静的フォーマットを予期しており、適応性がない場合、これは問題を引き起こす可能性があります。
以下は、時間部分がない場合とある場合の両方をシミュレートするために使用したコードです。
/**
* 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());
公式文書に従って:
各瞬間に正確に1つの有効なオフセットがあるため、瞬間のオフセットを取得するのは簡単です。対照的に、ローカル日時のオフセットを取得するのは簡単ではありません。次の3つのケースがあります。
つまり、2番目と3番目のケースは、toString()がISO-8601に準拠しない状況です。