web-dev-qa-db-ja.com

'Z'リテラルを使用したsimpledateformatによる日付の解析

私はこのような日付を解析しようとしています:

2010-04-05T17:16:00Z

これは http://www.ietf.org/rfc/rfc3339.txt による有効な日付です。 「Z」リテラルは、「UTCが指定された時間の優先参照ポイントであることを意味します。」

SimpleDateFormatとこのパターンを使用して解析しようとすると:

yyyy-MM-dd'T'HH:mm:ss

2010年4月5日月曜日17:16:00 EDTとして解析されます。

SimpleDateFormatは、次のパターンを使用して文字列を解析できません。

yyyy-MM-dd'T'HH:mm:ssz
yyyy-MM-dd'T'HH:mm:ssZ

SimpleDateFormatで使用するTimeZoneを明示的に設定して、期待される出力を取得できますが、それは必要ではないと思います。何か足りないものはありますか?代替の日付パーサーはありますか?

72
DanInDC

パターンに「z」日時コンポーネントを含めることは、タイムゾーン形式が General time zone "standard"に準拠する必要があることを示し、その例はPacific Standard Time; PST; GMT-08:00

「Z」は、タイムゾーンが RFC 822タイムゾーン 標準に準拠していることを示します。 -0800

DatatypeConverterが必要だと思います...

@Test
public void testTimezoneIsGreenwichMeanTime() throws ParseException {
    final Calendar calendar = javax.xml.bind.DatatypeConverter.parseDateTime("2010-04-05T17:16:00Z");
    TestCase.assertEquals("gotten timezone", "GMT+00:00", calendar.getTimeZone().getID());
}
30
Paul McKenzie

JavaはISO日付を正しく解析しません。

マッケンジーの答えに似ています。

解析する前にZを修正するだけです。

コード

String string = "2013-03-05T18:05:05.000Z";
String defaultTimezone = TimeZone.getDefault().getID();
Date date = (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).parse(string.replaceAll("Z$", "+0000"));

System.out.println("string: " + string);
System.out.println("defaultTimezone: " + defaultTimezone);
System.out.println("date: " + (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).format(date));

結果

string: 2013-03-05T18:05:05.000Z
defaultTimezone: America/New_York
date: 2013-03-05T13:05:05.000-0500
50
Alex

解析する日付はISO8601形式です。

Java 7では、タイムゾーンサフィックスを読み取って適用するパターンはyyyy-MM-dd'T'HH:mm:ssX

39
Dave Patterson

tl; dr

Instant.parse ( "2010-04-05T17:16:00Z" )

ISO 8601規格

あなたの文字列は ISO 8601 標準に準拠しています(言及されている RFC 3339 はプロファイルです)。

J.u.Dateを避ける

JavaにバンドルされているJava.util.Dateおよび.Calendarクラスは厄介なことで有名です。それらは避けてください。

代わりに、 Joda-Time ライブラリまたはJava 8の新しいJava.timeパッケージを使用してください。両方とも、日付の文字列表現の解析および生成のデフォルトとしてISO 8601を使用します時間値。

Java.time

Java.time フレームワークは、Java 8以降に組み込まれています。面倒な古いJava.util.Date/.Calendarクラスに取って代わります。新しいクラスは、非常に成功した Joda-Time 後継者として意図されたフレームワークで、概念は似ていますが再設計されています JSR 31 によって定義されています ThreeTen-Extra によって拡張されていますプロジェクト: チュートリアル を参照してください。

Java.timeのInstantクラスは、 [〜#〜] utc [〜#〜] タイムゾーンのタイムライン上の瞬間を表します。

入力文字列の末尾にあるZは、Zuluを表すUTCを意味します。このような文字列は、Instantクラスによって直接解析でき、フォーマッターを指定する必要はありません。

String input = "2010-04-05T17:16:00Z";
Instant instant = Instant.parse ( input );

コンソールにダンプします。

System.out.println ( "instant: " + instant );

インスタント:2010-04-05T17:16:00Z

そこから、タイムゾーン( ZoneId )を適用して、これを調整することができます InstantZonedDateTime 。議論と例については、スタックオーバーフローを検索してください。

Java.util.Date オブジェクトを使用する必要がある場合、静的メソッド Java.util.Date.from( Instant ) などの古いクラスに追加された新しい変換メソッドを呼び出して変換できます。 =。

Java.util.Date date = Java.util.Date.from( instant );

ジョーダタイム

Joda-Time 2.5の例。

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ):
DateTime dateTime = new DateTime( "2010-04-05T17:16:00Z", timeZone );

UTCに変換します。

DateTime dateTimeUtc = dateTime.withZone( DateTimeZone.UTC );

必要に応じて、Java.util.Dateに変換します。

Java.util.Date date = dateTime.toDate();
19
Basil Bourque

Date and Time Patternsテーブルの最後の行による Java 7 API

XタイムゾーンISO 8601タイムゾーン-08; -0800; -08:00

ISO 8601タイムゾーンの場合、次を使用する必要があります。

  • X(-08またはZ)、
  • XX(-0800またはZ)、
  • XXX(-08:00またはZ);

「2010-04-05T17:16:00Z」を解析するには、 "yyyy-MM-dd'T'HH:mm:ssX"のいずれかを使用できますまたは「yyyy-MM-dd'T'HH:mm:ssXX」または「yyyy-MM-dd'T'HH:mm:ssXXX」.

    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX").parse("2010-04-05T17:16:00Z"));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXX").parse("2010-04-05T17:16:00Z"));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").parse("2010-04-05T17:16:00Z"));

「Mon Apr 05 13:16:00 EDT 2010」を正しく印刷します

15
Legna

「X」は、秒の一部が存在しない場合にのみ機能します。つまり、のSimpleDateFormatパターン

「yyyy-MM-dd'T'HH:mm:ssX」

正しく解析します

「2008-01-31T00:00:00Z」

しかし

「yyyy-MM-dd'T'HH:mm:ss.SX」

解析しません

「2008-01-31T00:00:00.000Z」

悲しいことですが、秒の一部を含む日時は有効なISO日付ではないようです: http://en.wikipedia.org/wiki/ISO_8601

6
Sandy McPherson

SimpleDateFormatによって適切に解析されるように、タイムゾーンは「GMT + 00:00」または0000のようにする必要があります-Zをこの構造に置き換えることができます。

3
Cornel Creanga

Googleがapi-client-libraryで見つけた別の回答を提供します

try {
    DateTime dateTime = DateTime.parseRfc3339(date);
    dateTime = new DateTime(new Date(dateTime.getValue()), TimeZone.getDefault());
    long timestamp = dateTime.getValue();  // get date in timestamp
    int timeZone = dateTime.getTimeZoneShift();  // get timezone offset
} catch (NumberFormatException e) {
    e.printStackTrace();
}

インストールガイド、
https://developers.google.com/api-client-library/Java/google-api-Java-client/setup#download

これがAPIリファレンスです。
https://developers.google.com/api-client-library/Java/google-http-Java-client/reference/1.20.0/com/google/api/client/util/DateTime

DateTimeクラスのソースコード、
https://github.com/google/google-http-Java-client/blob/master/google-http-client/src/main/Java/com/google/api/client /util/DateTime.Java

DateTime単体テスト、
https://github.com/google/google-http-Java-client/blob/master/google-http-client/src/test/Java/com/google/api/client /util/DateTimeTest.Java#L121

2
Johnny

JSR-310に関して、別の興味深いプロジェクトは threetenbp です。

JSR-310は、Java SE 8の新しい日時ライブラリを提供します。このプロジェクトは、Java SE 6および7へのバックポートです。

Androidプロジェクトで作業している場合は、 ThreeTenABPライブラリ をチェックアウトすることをお勧めします。

compile "com.jakewharton.threetenabp:threetenabp:${version}"

JSR-310は、Java.time。*パッケージとしてJava 8に含まれていました。これは、Java JSR-310は、作成者であるStephen ColebourneによってJava 6にバックポートされました。

2
JJD

Restletプロジェクトには、RFC 3339の日付を解析できるInternetDateFormatクラスが含まれています。

Restlet InternetDateFormat

ただし、解析する前に、末尾の「Z」を「UTC」に置き換えるだけでよい場合があります。

2
Marcus Adams

Java 8では、事前定義されたDateTimeFormatter.ISO_DATE_TIMEを使用します

 DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
 ZonedDateTime result = ZonedDateTime.parse("2010-04-05T17:16:00Z", formatter);

その最も簡単な方法だと思います

1
JavaBohne

Java 8なのでZonedDateTime.parse("2010-04-05T17:16:00Z")を使用してください

0