web-dev-qa-db-ja.com

日付文字列をJava.util.Dateに解析するときの不正なパターン文字「T」

日付文字列があり、それをJava Date APIを使用して通常の日付に解析したいのですが、以下が私のコードです:

public static void main(String[] args) {
    String date="2010-10-02T12:23:23Z";
    String pattern="yyyy-MM-ddThh:mm:ssZ";
    SimpleDateFormat sdf=new SimpleDateFormat(pattern);
    try {
        Date d=sdf.parse(date);
        System.out.println(d.getYear());
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

ただし、例外が発生しました:Java.lang.IllegalArgumentException: Illegal pattern character 'T'

だから、文字列を分割して手動で解析する必要があるのだろうか?

ところで、私はTの両側に一重引用符を追加しようとしました:

String pattern="yyyy-MM-dd'T'hh:mm:ssZ";

また、機能しません。

158
hguser

Java 8以降の更新

Javaの最新バージョンでは、壊れたJava.util.Dateの代わりにInstantを使用する必要があるため、今すぐInstant.parse("2015-04-28T14:23:38.521Z")を実行して正しいことを取得できます。

DateTimeFormatterの代わりにSimpleDateFormatterも使用する必要があります。

元の回答:

以下の説明は、形式が表すものとして引き続き有効です。しかし、それはJava 8が遍在する前に書かれたため、Java 8以上を使用している場合は使用すべきではない古いクラスを使用します。

これは、示されているように、末尾のZを持つ入力で機能します。

パターンでは、Tは、両側に'でエスケープされます。

末尾のZのパターンは、XXXのJavaDocに記載されているように、実際はSimpleDateFormatですが、Zは古いTimeZone情報のマーカーも同様です。

Q2597083.Java

import Java.text.SimpleDateFormat;
import Java.util.Calendar;
import Java.util.Date;
import Java.util.GregorianCalendar;
import Java.util.TimeZone;

public class Q2597083
{
    /**
     * All Dates are normalized to UTC, it is up the client code to convert to the appropriate TimeZone.
     */
    public static final TimeZone UTC;

    /**
     * @see <a href="http://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations">Combined Date and Time Representations</a>
     */
    public static final String ISO_8601_24H_FULL_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";

    /**
     * 0001-01-01T00:00:00.000Z
     */
    public static final Date BEGINNING_OF_TIME;

    /**
     * 292278994-08-17T07:12:55.807Z
     */
    public static final Date END_OF_TIME;

    static
    {
        UTC = TimeZone.getTimeZone("UTC");
        TimeZone.setDefault(UTC);
        final Calendar c = new GregorianCalendar(UTC);
        c.set(1, 0, 1, 0, 0, 0);
        c.set(Calendar.MILLISECOND, 0);
        BEGINNING_OF_TIME = c.getTime();
        c.setTime(new Date(Long.MAX_VALUE));
        END_OF_TIME = c.getTime();
    }

    public static void main(String[] args) throws Exception
    {

        final SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_24H_FULL_FORMAT);
        sdf.setTimeZone(UTC);
        System.out.println("sdf.format(BEGINNING_OF_TIME) = " + sdf.format(BEGINNING_OF_TIME));
        System.out.println("sdf.format(END_OF_TIME) = " + sdf.format(END_OF_TIME));
        System.out.println("sdf.format(new Date()) = " + sdf.format(new Date()));
        System.out.println("sdf.parse(\"2015-04-28T14:23:38.521Z\") = " + sdf.parse("2015-04-28T14:23:38.521Z"));
        System.out.println("sdf.parse(\"0001-01-01T00:00:00.000Z\") = " + sdf.parse("0001-01-01T00:00:00.000Z"));
        System.out.println("sdf.parse(\"292278994-08-17T07:12:55.807Z\") = " + sdf.parse("292278994-08-17T07:12:55.807Z"));
    }
}

次の出力を生成します。

sdf.format(BEGINNING_OF_TIME) = 0001-01-01T00:00:00.000Z
sdf.format(END_OF_TIME) = 292278994-08-17T07:12:55.807Z
sdf.format(new Date()) = 2015-04-28T14:38:25.956Z
sdf.parse("2015-04-28T14:23:38.521Z") = Tue Apr 28 14:23:38 UTC 2015
sdf.parse("0001-01-01T00:00:00.000Z") = Sat Jan 01 00:00:00 UTC 1
sdf.parse("292278994-08-17T07:12:55.807Z") = Sun Aug 17 07:12:55 UTC 292278994
181
user177800

tl; dr

Instant.parse( "2010-10-02T12:23:23Z" )

ISO 8601

この形式は、日時文字列形式の ISO 8601 標準で定義されています。

両方:

…文字列の解析と生成には、デフォルトでISO 8601形式を使用します。

通常、古いJava.util.Date/。CalendarおよびJava.text.SimpleDateFormatクラスを使用することは避けてください。これらのクラスは、面倒で混乱を招き、欠陥があることで有名です。相互運用に必要な場合は、前後に変換できます。

Java.time

Java 8以降には、新しい Java.time フレームワークが組み込まれています。 JSR-31 によって定義され、 ThreeTen-Extra プロジェクトによって拡張された Joda-Time に​​触発されました。

Instant instant = Instant.parse( "2010-10-02T12:23:23Z" );  // `Instant` is always in UTC.

古いクラスに変換します。

Java.util.Date date = Java.util.Date.from( instant );  // Pass an `Instant` to the `from` method.

タイムゾーン

必要に応じて、タイムゾーンを割り当てることができます。

ZoneId zoneId = ZoneId.of( "America/Montreal" ); // Define a time zone rather than rely implicitly on JVM’s current default time zone.
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );  // Assign a time zone adjustment from UTC.

変換します。

Java.util.Date date = Java.util.Date.from( zdt.toInstant() );  // Extract an `Instant` from the `ZonedDateTime` to pass to the `from` method.

ジョーダタイム

更新:Joda-Timeプロジェクトは現在、メンテナンスモードになっています。チームは、Java.timeクラスへの移行を推奨しています。

Joda-Time 2.8のサンプルコードを次に示します。

org.joda.time.DateTime dateTime_Utc = new DateTime( "2010-10-02T12:23:23Z" , DateTimeZone.UTC );  // Specifying a time zone to apply, rather than implicitly assigning the JVM’s current default.

古いクラスに変換します。 j.u.Dateにタイムゾーンを割り当てることはできないため、割り当てられたタイムゾーンは変換で失われることに注意してください。

Java.util.Date date = dateTime_Utc.toDate(); // The `toDate` method converts to old class.

タイムゾーン

必要に応じて、タイムゾーンを割り当てることができます。

DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
DateTime dateTime_Montreal = dateTime_Utc.withZone ( zone );

Java.timeについて

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

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

詳細については、 Oracle Tutorial を参照してください。また、Stack Overflowで多くの例と説明を検索してください。仕様は JSR 31 です。

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

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

  • Java SE 8Java SE 9 、およびそれ以降
    • ビルトイン。
    • 実装がバンドルされた標準Java AP​​Iの一部。
    • Java 9は、いくつかのマイナーな機能と修正を追加します。
  • Java SE 6 および Java SE 7
    • Java.time機能の多くは、 ThreeTen-Backport のJava 6および7にバックポートされています。
  • Android
    • Androidの後のバージョンは、Java.timeクラスの実装をバンドルします。
    • 以前のAndroid(<26)の場合、 ThreeTenABP プロジェクトはThreeTen-Backport(上記を参照)に適合します。 _を参照ThreeTenABPの使用方法…

ThreeTen-Extra プロジェクトは、Java.timeを追加のクラスで拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある証明の場です。ここでは、 IntervalYearWeekYearQuarter 、および more

21
Basil Bourque