Karakter pola ilegal 'T' saat mem-parsing string tanggal ke java.util.Date

182

Saya memiliki string tanggal dan saya ingin menguraikannya ke tanggal normal menggunakan java Date API, berikut ini adalah kode saya:

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();
    }
}

Namun saya mendapat pengecualian: java.lang.IllegalArgumentException: Illegal pattern character 'T'

Jadi saya ingin tahu apakah saya harus memisahkan string dan menguraikannya secara manual?

BTW, saya telah mencoba menambahkan karakter kutipan tunggal di kedua sisi T:

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

Itu juga tidak bekerja.

hguser
sumber
1
Anda tahu apa artinya "T" ini? Sejauh yang saya pikir seluruh tanggal bersama dengan 'T' harus dikonversi ke tanggal (tidak melewatkannya melalui 'Kutipan Tunggal', tetapi hal yang kami lewatkan adalah pola parse.
coding_idiot
9
The Tsingkatan waktu dan merupakan bagian dari ISO8601 standar untuk waktu tanggal internasional format.
1
Itu aneh. Membungkus Tdalam tanda kutip tunggal bekerja untuk saya (setidaknya dalam hal menyelesaikan kesalahan parse).
Agi Hammerthief

Jawaban:

204

Pembaruan untuk Java 8 dan lebih tinggi

Anda sekarang dapat dengan mudah melakukan Instant.parse("2015-04-28T14:23:38.521Z")dan mendapatkan hal yang benar sekarang, terutama karena Anda harus menggunakan Instantalih-alih rusak java.util.Datedengan versi terbaru dari Java.

Anda harus menggunakan, DateTimeFormatterbukan SimpleDateFormatterjuga.

Jawaban asli:

Penjelasan di bawah ini masih valid seperti apa formatnya wakili. Tapi itu ditulis sebelum Java 8 ada di mana-mana sehingga menggunakan kelas lama yang tidak boleh Anda gunakan jika Anda menggunakan Java 8 atau lebih tinggi.

Ini bekerja dengan input dengan trailing Zseperti yang ditunjukkan:

Dalam pola Titu lolos dengan 'di kedua sisi.

Pola Zpada akhirnya sebenarnya XXXseperti yang didokumentasikan dalam JavaDoc untuk SimpleDateFormat, itu tidak begitu jelas tentang bagaimana sebenarnya menggunakannya karena Zmerupakan penanda untuk TimeZoneinformasi lama juga.

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"));
    }
}

Menghasilkan output berikut:

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

sumber
26

tl; dr

Gunakan java.time.Instantkelas untuk mem-parsing teks dalam format standar ISO 8601, mewakili momen dalam UTC.

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

ISO 8601

Format itu ditentukan oleh standar ISO 8601 untuk format string tanggal-waktu.

Kedua:

... gunakan format ISO 8601 secara default untuk parsing dan menghasilkan string.

Anda umumnya harus menghindari menggunakan kelas java.util.Date /.Calendar & java.text.SimpleDateFormat yang lama karena mereka terkenal merepotkan, membingungkan, dan cacat. Jika diperlukan untuk beroperasi, Anda dapat mengonversi ke sana kemari.

waktu java

Dibangun ke dalam Java 8 dan yang lebih baru adalah kerangka java.time baru . Terinspirasi oleh Joda-Time , didefinisikan oleh JSR 310 , dan diperpanjang oleh proyek ThreeTen-Extra .

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

Konversikan ke kelas lama.

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

Zona waktu

Jika perlu, Anda dapat menetapkan zona waktu.

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.

Mengubah.

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

Joda-Time

UPDATE: Proyek Joda-Time sekarang dalam mode pemeliharaan. Tim menyarankan migrasi ke kelas java.time .

Berikut adalah beberapa contoh kode dalam 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.

Konversi ke kelas lama. Perhatikan bahwa zona waktu yang ditetapkan hilang dalam konversi, karena juDate tidak dapat ditetapkan zona waktu.

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

Zona waktu

Jika perlu, Anda dapat menetapkan zona waktu.

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

Tabel tipe waktu-tanggal di Jawa, baik yang modern maupun yang lama.


Tentang java.time

The java.time kerangka dibangun ke Jawa 8 dan kemudian. Kelas-kelas ini menggantikan tua merepotkan warisan kelas tanggal-waktu seperti java.util.Date, Calendar, & SimpleDateFormat.

Proyek Joda-Time , sekarang dalam mode pemeliharaan , menyarankan migrasi ke kelas java.time .

Untuk mempelajari lebih lanjut, lihat Tutorial Oracle . Dan cari Stack Overflow untuk banyak contoh dan penjelasan. Spesifikasi adalah JSR 310 .

Anda dapat bertukar objek java.time secara langsung dengan database Anda. Gunakan driver JDBC yang sesuai dengan JDBC 4.2 atau yang lebih baru. Tidak perlu untuk string, tidak perlu untuk java.sql.*kelas.

Di mana mendapatkan kelas java.time?

Tabel mana perpustakaan java.time untuk digunakan dengan versi Java atau Android.

Proyek ThreeTen-Extra memperpanjang java.time dengan kelas tambahan. Proyek ini adalah ajang pembuktian untuk kemungkinan penambahan masa depan ke java.time. Anda mungkin menemukan beberapa kelas berguna di sini seperti Interval, YearWeek, YearQuarter, dan lebih .

Basil Bourque
sumber
1
@AalapPatel Sadarilah bahwa proyek Joda-Time sekarang dalam mode pemeliharaan. Tim menyarankan migrasi ke kelas java.time. Kedua upaya tersebut dipimpin oleh orang yang sama, Stephen Colebourne.
Basil Bourque
Terima kasih, saya menggunakannya untuk mendapatkan milidetik dari server yang mengembalikan waktu UTC dan / atau waktu lokal dan berfungsi dengan baik untuk saya dalam kasus ini ..
Aalap Patel
Instant.parse membutuhkan min api level 26 di android
Naveed Ahmad
1
@NaveedAhmad Lihat butir di bawah Jawaban tentang proyek ThreeTen-Backport dan ThreeTenABP .
Basil Bourque
0

Ada dua jawaban di atas yang up-to-sekarang dan keduanya panjang (dan tl; dr terlalu pendek IMHO), jadi saya menulis ringkasan dari pengalaman saya mulai menggunakan perpustakaan java.time baru (berlaku sebagaimana tercantum dalam jawaban lain untuk versi Java 8+). ISO 8601 menetapkan cara standar untuk menulis tanggal: YYYY-MM-DDjadi format waktu-tanggal hanya seperti di bawah ini (bisa 0, 3, 6 atau 9 digit selama milidetik) dan tidak perlu memformat string:

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();
    }
}

Saya tidak membutuhkannya, tetapi karena mendapatkan tahun adalah dalam kode dari pertanyaan, maka:
lebih sulit, tidak dapat dilakukan Instantsecara langsung, dapat dilakukan melalui Calendarcara pertanyaan. Dapatkan nilai integer tahun ini di Jawa dan Konversi java. waktu untuk Kalender tetapi IMHO karena formatnya diperbaiki substring lebih mudah digunakan:

myDate.toString().substring(0,4);
Alexei Martianov
sumber