8

Java 7 では、SimpleDateFormatクラスで ISO 8601 形式のサポートが導入されましたX(小文字または大文字の代わりにZ)。Java 6 でこのような形式をサポートするには前処理が必要になるため、最善の方法は問題です。

この新しい形式は、Z(大文字の Z) のスーパーセットであり、2 つのバリエーションが追加されています。

  1. 「分」フィールドはオプションです (つまり、4 桁ではなく 2 桁のタイムゾーンが有効です)。
  2. 2 桁の「時」フィールドと 2 桁の「分」フィールドを区切るには、コロン文字 (':') を使用できます)。

のJava 7 ドキュメントSimpleDateFormatからわかるように、次の 3 つの形式が現在有効であり (Java 6 でカバーされている 2 番目の形式のみではなくZ)、もちろん同等です。

  1. -08
  2. -0800
  3. -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 パスを使用した方が高速な場合は、このアプローチが適しています)。

4

2 に答える 2

6

これを使用できるようです:

import java.util.Calendar;
import javax.xml.bind.DatatypeConverter;

public class TestISO8601 {
    public static void main(String[] args) {
        parse("2012-10-01T19:30:00+02:00"); // UTC+2
        parse("2012-10-01T19:30:00Z");      // UTC
        parse("2012-10-01T19:30:00");       // Local
    }
    public static Date parse(final String str) {
        Calendar c = DatatypeConverter.parseDateTime(str);
        System.out.println(str + "\t" + (c.getTime().getTime()/1000));
        return c.getTime();
    }
}
于 2013-01-05T22:33:43.787 に答える
3

Java 6 では、Java の最新の日付と時刻の API である java.time を使用できます。ISO 8601 を適切にサポートしています。

import org.threeten.bp.OffsetDateTime;
import org.threeten.bp.format.DateTimeFormatter;

public class DemoIso8601Offsets {
    public static void main(String[] args) {
        System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+0200", 
                DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXX")));
        System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+02", 
                DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX")));
        System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+02:00"));
        System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00Z"));
    }
}

このプログラムからの出力は次のとおりです。

2012-10-01T19:30+02:00
2012-10-01T19:30+02:00
2012-10-01T19:30+02:00
2012-10-01T19:30Z

プロジェクト設定に ThreeTen Backport ライブラリを追加する必要があります。

  • Java 8 以降および新しい Android デバイス (API レベル 26 以降) では、最新の API が組み込まれています。
  • Java 6 および 7 では、新しいクラスのバックポートである ThreeTen Backport を取得します (JSR 310 用の ThreeTen。下部のリンクを参照してください)。
  • (古い) Android では、ThreeTen Backport の Android 版を使用します。それは ThreeTenABP と呼ばれます。org.threeten.bpまた、サブパッケージを使用して日付と時刻のクラスをインポートしてください。

コードからわかるように、オフセットの形式を指定するフォーマッターが必要ですが、(そしてそれ+02も) デフォルトの形式に準拠しており、指定する必要はありません。+0200+02:00Z

同じフォーマッタを使用してすべてのオフセット形式を解析できますか?

混合データを読み取る場合、各オフセット形式を特別に処理する必要はありません。フォーマット パターン文字列でオプションの部分を使用することをお勧めします。

    DateTimeFormatter allInOne 
            = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[XXX][XX][X]");
    System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+0200", allInOne));
    System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+02", allInOne));
    System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+02:00", allInOne));
    System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00Z", allInOne));

出力は上記と同じです。の角括弧は、 format または が存在する可能性があることを意味[XXX][XX][X]します。+02:00+0200+02

リンク

于 2018-08-25T13:29:47.387 に答える