web-dev-qa-db-ja.com

java)のRFC3339日時文字列を解析するために使用するパターン

これは多くの異なる答えを持つ一般的な質問のようです。あなたが答える前に、私は joda-timeatomdate の両方を使用しました、そしてそれらはうまく機能します。ここでの私の関心は、使用するライブラリではなく、JavaでRFCパターンを定義する方法を明確にすることです。


研究

私の理解と この回答 RFC3339はISO8601のプロファイルです。PHP 明確に定義 RFC3339の日時パターンはY-m-d\TH:i:sP。この定義をJava 7(私の知る限り)に転送すると、最終的にはこれになります(これは この回答 でも参照されます):

// example "2005-08-15T15:52:01+00:00"
pattern = "yyyy-MM-dd'T'HH:mm:ssXXX";

ただし、 this one のようないくつかのスタックオーバーフローの回答は、RFC 3339の正しいパターンとしてこれらの1つ(または両方)を指しています

// example "2016-11-01T20:44:39Z"
pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'";

// example "1937-01-01T12:00:27.87Z"
pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

問題をさらに複雑にするために、公式 RFC 3339 ドキュメントには、次のすべての例がリストされています(対応するパターンになると思うものを追加しました)。

// 1996-12-19T16:39:57-08:00
pattern = "yyyy-MM-dd'T'HH:mm:ssXXX";

// 1990-12-31T23:59:60Z
pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'";

// 1990-12-31T15:59:60-08:00
pattern = "yyyy-MM-dd'T'HH:mm:ssXXX";

// 1937-01-01T12:00:27.87+00:20
pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";

サイドノート:AndroidはタイムゾーンのXXXパターンをサポートしていませんが、代わりにZZZZZを使用できます この答え

私を混乱させているのは、RFC822とRFC2822がそれぞれ1つのパターンで具体的に参照されているのを見たことがあるので、RFC3339も1つのパターン一致に要約できると思いました。

static String RFC_822 = "EEE, dd MMM yy HH:mm:ss zzz";
static String RFC_2822 = "EEE, dd MMM yyyy HH:mm:ss zzz";

私の結論

Phpとは異なり、RFC3339は単一の一致する式のみを使用してJavaで表すことはできません。代わりに、これらはすべて有効なRFC 3339パターンであり、SimpleDateFormatを介して日時文字列を解析するときにチェックする必要があります。

static String[] RFC_3339_VARIANTS = {
        "yyyy-MM-dd'T'HH:mm:ss'Z'",
        "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
        "yyyy-MM-dd'T'HH:mm:ssXXX",
        "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
};

更新

問題を複雑にするために、SimpleDateFormatは「Z」タイムゾーンリテラルを正しく処理していないようです。 UTCを想定する代わりに、デフォルトでPSTまたは現地時間のいずれかになります(どちらかはわかりません)。つまり、この動作を修正するには、「Z」リテラルを+00:00に手動で置き換える必要があるかもしれません。


要旨

提案されているように、現在実行中のコードを含むユーティリティクラスGistを作成しました。これはAndroidで実行され、Java 7+とも互換性があります。質問があるか、コメントを残してください。十分な関心があれば、移動できます。他の人が貢献できるようにGithubに転送します。

https://Gist.github.com/oseparovic/d9ee771927ac5f3aefc8ba0b99c0cf38


私はこれを正しく理解していますか、それとも完全にオフですか? Java 7でRFC3339文字列を解析する方法について皆さんが提供できる説明をいただければ幸いです。

10
alexgophermix

あなたは基本的にあなた自身の質問にほとんど答えましたが、あなたの要点でさえすべての場合に正しいわけではありません...つまり、あなたが持っている2つよりもさらに多くのパターンが必要です(たとえば、ナノ秒を処理するため)。

そしてこれが、JodaとJava 8がISO8601(スーパーセット)用の特別なパーサーを持っている理由です。

他のライブラリへの参照は必要ないことはわかっていますが、Java 8を使用している、またはRFC 3339に明示的に制限したい他のライブラリ(joda isoパーサーは、より多くの形式を使用すると思います) rfc 3339)このライブラリがあります: https://github.com/ethlo/it

1
Adam Gent