web-dev-qa-db-ja.com

ISO8601日付文字列をUTCタイムゾーンで日付まで解析します

JavaScriptアプリケーションとの間で日付をシリアル化/非シリアル化しようとしています。

サーバー側では、Javaを使用しており、JodaTimeがインストールされています。 UTCタイムゾーンでISOにシリアル化する方法を見つけましたが、逆の操作を行う方法を見つけることができません。

これが私のコードです

public static String getIsoDate( Date date )
{
    SimpleDateFormat  dateToIsoDateString = new SimpleDateFormat( ISO_8601_DATE_FORMAT );
    TimeZone tz = TimeZone.getTimeZone("UTC");
    dateToIsoDateString.setTimeZone( tz );
    return dateToIsoDateString.format( date );
}

// this will return a date with GMT timezone
public static Date getDateFromIsoDateString( String iso8601date )
{
    DateTimeFormatter jodaParser = ISODateTimeFormat.dateTimeNoMillis();
    return jodaParser.parseDateTime( iso8601date ).toDate();
}

Jodaを使用してもしなくてもかまいませんが、迅速で実用的なソリューションが必要です。

14
Dimitri Kopriwa

Java 7以前を使用している場合は、これを参照できます post

Java 8を使用している場合、次のようにすることができます。

    DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;
    TemporalAccessor accessor = timeFormatter.parse("2015-10-27T16:22:27.605-07:00");

    Date date = Date.from(Instant.from(accessor));
    System.out.println(date);

更新

コメントの@BasilBourqueで指摘されているように、 TemporalAccessor はJavaフレームワークレベルのインターフェースであり、アプリケーションコードでの使用はお勧めできません。具象を使用することをお勧めしますインターフェイスではなくクラス。

このインターフェイスはフレームワークレベルのインターフェイスであり、アプリケーションコードで広く使用することはできません。代わりに、アプリケーションはLocalDateなどの具象型のインスタンスを作成して渡します。これには多くの理由があり、その一部は、このインターフェースの実装がISO以外のカレンダーシステムにある可能性があることです。問題の詳細については、ChronoLocalDateを参照してください。

LocalDateLocalDateTimeOffsetDateTimeZonedDateTime などの使用可能ないくつかの具象クラスがあります。

DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;

OffsetDateTime offsetDateTime = OffsetDateTime.parse("2015-10-27T16:22:27.605-07:00", timeFormatter);

Date date = Date.from(Instant.from(offsetDateTime));
System.out.println(date);

tl; dr

OffsetDateTime.parse( "2015-10-27T16:22:27.605-07:00" )
.toInstant()
.toString()

2015-10-27T23:22:27.605Z

細部

あなたの質問は明確で具体的ではありません。おそらく、これらの小さな例が役立つでしょう。古いJava.util.Dateクラスと.CalendarクラスをJoda-Timeと混在させると混乱を招く可能性があります。 Joda-Timeは、拡張ではなく、これらのクラスを完全に置き換えます

Java.time

最新のJava.timeクラスは、Javaのレガシー日時クラスと、インスピレーションを提供したJoda-Timeライブラリの両方に取って代わります。

OffsetDateTime

OffsetDateTime クラスは、実時間を決定する特定のUTCからのオフセットでタイムライン上の瞬間を表します。

Java.timeクラスは、文字列の解析/生成時に、デフォルトで標準の ISO 8601 形式を使用します。したがって、フォーマットパターンを指定する必要はありません。

OffsetDateTime odt = OffsetDateTime.parse( "2015-10-27T16:22:27.605-07:00" ) ;

Instant

UTCから7時間遅れのオフセットからUTC自体に調整するには、時刻に7時間を追加し、必要に応じて日付をロールオーバーする必要があります。 OffsetDateTimeクラスでこの作業を行うことができます。 ZoneOffset.UTC定数を使用してUTCを指定します。

OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ) ;

odtUtc.toString():2015-10-27T23:22:27.605Z

このUTC値をコードで多く使用していて、通常は使用する必要がある場合は、Instantオブジェクトを使用する方がわかりやすいかもしれません。 Instantは、定義上、UTCではalwaysです。 InstantからOffsetDateTimeを抽出できます。

Instant instant = odt.toInstant() ;

instant.toString():2015-10-27T23:22:27.605Z

上記の3つのオブジェクト(odtodtUtcinstant)はすべて、非常に同じ瞬間、つまりタイムライン上の同じポイントを表していることに注意してください。唯一異なるのは、実時間です。

ZonedDateTime

ちなみに、同じ瞬間を特定の地域の人々が使用している実時間に合わせて調整したい場合は、ZoneIdを使用してタイムゾーンを指定し、ZonedDateTimeオブジェクトを取得します。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

zdt.toString():2015-10-27T19:22:27.605-04:00 [アメリカ/モントリオール]

Java.timeで具象クラスを使用する

always_a_rookie_to_learnによる回答 は、上記のアプローチに似ていますが、インターフェース TemporalAccessor を使用します。一般に、Javaではより高いインターフェースとスーパークラスを使用することをお勧めします。しかし、ここではありません。 Java.timeのドキュメントでは、それらの設計では、アプリでより具体的なクラスを使用するつもりであると説明されています。抽象化は、通常、フレームワーク内でのみ内部的に使用されます。

この質問の特定のケースでは、クラスOffsetDateTimeではなくTemporalAccessorが適切です。


Java.timeについて

Java.time フレームワークはJava 8以降に組み込まれています。これらのクラスは厄介な古い レガシーに取って代わりますJava.util.DateCalendar 、& SimpleDateFormat などの日時クラス.

Joda-Time プロジェクトは現在 メンテナンスモード であり、 Java.time クラスへの移行を推奨しています。

詳細については、 Oracleチュートリアル を参照してください。スタックオーバーフローで多くの例と説明を検索してください。仕様は JSR 310 です。

Java.timeオブジェクトをデータベースと直接交換できます。 JDBC 4.2 以降に準拠した JDBCドライバー を使用します。文字列も、Java.sql.*クラスも必要ありません。

Java.timeクラスはどこで入手できますか?

ThreeTen-Extra プロジェクトは、追加のクラスでJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性があることを証明する場です。 IntervalYearWeekYearQuartermore などの便利なクラスがここにあります。


ジョーダタイム

更新:のJoda-Timeプロジェクトはメンテナンスモードであり、Java.timeクラスへの移行を推奨します。このセクションは、履歴のためにそのまま残されています。

Joda-Timeのデフォルトは ISO 8601 で、文字列は解析と生成の両方が行われます。 Joda-Time にはISO 8601のデフォルトのパーサーが組み込まれているため、準拠する文字列をコンストラクターまたは静的parseメソッドに渡すだけです。

Java.util.Date date = new DateTime( "2010-01-01T12:00:00+01:00Z" ).toDate();

可能な場合は、Java.util.Dateと.Calendarを避け、stickとJoda-Timeを使用して、DateTimeなどのクラスを作成します。他のクラスで必要な場合にのみ.Dateを使用してください。

DateTime dateTimeUtc = new DateTime( someJavaDotUtilDotDate, DateTimeZone.UTC ); // Joda-Time can convert from Java.util.Date type which has no time zone.
String output = dateTime.toString(); // Defaults to ISO 8601 format.
DateTime dateTimeUtc2 = new DateTime( output, DateTimeZone.UTC ); // Joda-Time can parse ISO 8601 strings.

プレゼンテーションでは、ユーザーが期待するタイムゾーンに調整します。

DateTime dateTimeMontréal = dateTimeUtc.withZone( DateTimeZone.forID( "America/Montreal" ) );
10
Basil Bourque

Java8のネイティブソリューション

Date.from(ZonedDateTime.parse("1994-11-05T08:15:30+05:30").toInstant())

Date.from(ZonedDateTime.parse("1994-11-05T13:15:30Z").toInstant())
1
stonelazy