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


182

日付文字列があり、それを通常の日付に解析したいのですが、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";

また、機能しません。


1
この「T」の意味を知っていますか?「T」と一緒に日付全体を日付に変換する必要があると思う限り(「単一引用符」をスキップしないでください)、ただし欠落しているのは解析パターンです。
coding_idiot

9
時間T略で、ISO8601標準の国際日付時刻形式の一部です。

1
それは変です。T一重引用符で囲むとうまくいきました(少なくとも解析エラーの解決という点では)。
Agi Hammerthief

回答:


203

Java 8以降のアップデート

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

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

元の回答:

以下の説明は、フォーマットが表すものとして引き続き有効です。ただし、Java 8が広く普及する前に作成されたため、Java 8以降を使用している場合は使用してはならない古いクラスを使用します。

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

パターンでT'、どちらかでエスケープされます。

Z最後ののパターンは、実際XXXにはJavaDoc forに記載されているとおりです。古い情報のマーカーでもあるため、 SimpleDateFormat実際の使用方法はあまり明確ではありません。ZTimeZone

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

26

tl; dr

java.time.Instantクラスを使用して、UTCの瞬間を表す標準ISO 8601形式のテキストを解析します。

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 310で定義されたJoda- Timeに触発され、ThreeTen-Extraプロジェクトによって拡張されました。

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.

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

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の日時タイプの表。


java.timeについて

java.timeのフレームワークは、Java 8に組み込まれており、後にされています。これらのクラスは面倒古い取って代わるレガシーのような日付時刻クラスをjava.util.DateCalendar、& SimpleDateFormat

ジョダタイムプロジェクトは、今でメンテナンスモードへの移行をアドバイスjava.timeのクラス。

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

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

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

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

JavaまたはAndroidのどのバージョンで使用するjava.timeライブラリの表。

ThreeTen-エクストラプロジェクトでは、追加のクラスでjava.timeを拡張します。このプロジェクトは、java.timeに将来追加される可能性があることを証明する場です。あなたはここにいくつかの有用なクラスのような見つけることがIntervalYearWeekYearQuarter、および多くを


1
@AalapPatel Joda-Timeプロジェクトがメンテナンスモードになっていることに注意してください。チームは、java.timeクラスへの移行を推奨しています。どちらの取り組みも、同じ人物であるスティーブンコールボーンが主導しています。
バジルブルク

..私は、サーバーからのミリ秒を取得するためにそれを使用する、ありがとうUTC時刻および/またはロケールの時間を返され、この場合には私のためによく働く
Aalapパテル

Instant.parseにはAndroidで最小APIレベル26が必要
Naveed Ahmad

1
@NaveedAhmad ThreeTen-BackportおよびThreeTenABPプロジェクトに関する回答の下部にある箇条書きを参照してください。
バジルブルク

0

これまでに2つの回答があり、どちらも長い(そしてtl; dr IMHOが短すぎる)ので、新しいjava.timeライブラリの使用を開始した経験から要約を書きます(Javaバージョンの他の回答で述べたように適用可能) 8+)。ISO 8601は日付を書き込むための標準的な方法を設定します。YYYY-MM-DDそのため、日付と時刻の形式は以下のとおり(ミリ秒の場合は0、3、6、または9桁)であり、フォーマット文字列は必要ありません。

import java.time.Instant;
public static void main(String[] args) {
    String date="2010-10-02T12:23:23Z";
    try {
        Instant myDate = Instant.parse(date);
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

私はそれを必要としませんでしたが、質問からコードで年を取得するので、
それは難しいです、Instant直接行うことはできませんCalendar、質問を介して行うことができますJavaで現在の年の整数値を取得してJava変換します。カレンダーまでの時間ですが、形式が固定されているため、IMHOは部分文字列を使用する方が簡単です。

myDate.toString().substring(0,4);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.