Java 7 では、SimpleDateFormat
クラスで ISO 8601 形式のサポートが導入されましたX
(小文字または大文字の代わりにZ
)。Java 6 でこのような形式をサポートするには前処理が必要になるため、最善の方法は問題です。
この新しい形式は、Z
(大文字の Z) のスーパーセットであり、2 つのバリエーションが追加されています。
- 「分」フィールドはオプションです (つまり、4 桁ではなく 2 桁のタイムゾーンが有効です)。
- 2 桁の「時」フィールドと 2 桁の「分」フィールドを区切るには、コロン文字 (':') を使用できます)。
のJava 7 ドキュメントSimpleDateFormat
からわかるように、次の 3 つの形式が現在有効であり (Java 6 でカバーされている 2 番目の形式のみではなくZ
)、もちろん同等です。
- -08
- -0800
- -08:00
このような「拡張された」タイムゾーン形式を常に区切り文字として「:」でサポートする特殊なケースに関する以前の質問で説明したように、Java 7 の機能を Java 6 にバックポートする最良の方法は、クラスをサブクラス化し、そのメソッドSimpleDateformat
をオーバーライドすることです。 parse()
、つまり:
public Date parse(String date, ParsePosition pos)
{
String iso = ... // Replace the X with a Z timezone string, using a regex
if (iso.length() == date.length())
{
return null; // Not an ISO 8601 date
}
Date parsed = super.parse(iso, pos);
if (parsed != null)
{
pos.setIndex(pos.getIndex()+1); // Adjust for ':'
}
return parsed;
}
上記のサブクラスSimpleDateFormat
化されたオブジェクトは、対応するZ
ベースのパターンで初期化する必要がExtendedSimpleDateformat
あります。yyyy-MM-dd'T'HH:mm:ssX
new ExtendedSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
前述の以前の質問:(?=[0-9]{2}$)
では、「:」を取り除くために正規表現が提案されており、同様の質問(?<=[+-]\d{2})$
では、必要に応じて「分」フィールドを追加するために正規表現が提案されてい00
ます。
明らかに、2 つの置換を正常に実行すると、完全な機能を実現するために使用できます。したがって、オーバーライドされたメソッドのiso
ローカル変数は次のように設定されます。parse()
iso = date.replaceFirst(":(?=[0-9]{2}$)","");
また
iso = iso.replaceFirst("(?<=[+-]\\d{2})$", "00");
間にif
チェックを入れて、pos
後で値が適切に設定されていることを確認し、length()
以前の比較にも使用します。
問題は、単一の正規表現pos
を使用して、長さを不必要にチェックせず、後で数行を正しく設定するために必要な情報を含めて、同じ効果を達成できるかということです。
この実装は、任意の形式 (完全に非日付であっても) の非常に多数の文字列フィールドを読み取り、その形式に準拠するものだけを選択して、解析された JavaDate
オブジェクトを返すコードを対象としています。
そのため、精度と速度の両方が最も重要です (つまり、2 パスを使用した方が高速な場合は、このアプローチが適しています)。