Java.util.Date için bir tarih dizesi ayrıştırılırken geçersiz desen karakteri 'T'


182

Bir tarih dizesi var ve ben java Tarih API kullanarak normal tarihe ayrıştırmak istiyorum, aşağıdaki benim kod:

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

Ancak bir istisna var: java.lang.IllegalArgumentException: Illegal pattern character 'T'

Ben dize bölmek ve elle ayrıştırmak zorunda mıyım acaba?

BTW, T'nin her iki tarafına tek bir tırnak karakteri eklemeye çalıştım:

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

Ayrıca çalışmaz.


1
bu "T" nin ne anlama geldiğini biliyor musunuz? Bildiğim kadarıyla 'T' ile birlikte tüm tarih tarihe dönüştürülmelidir ('Tek Alıntılar' ile
atlanmamakla

9
TAçılımı zaman ve bir parçası olan ISO8601 biçimlendirme uluslararası tarih kez standart.

1
Bu garip. TTek tırnak içinde kaydırma benim için çalıştı (en azından ayrıştırma hatasını çözme açısından).
Agi Hammerthief

Yanıtlar:


204

Java 8 ve üstü için güncelleme

Artık sadece Instant.parse("2015-04-28T14:23:38.521Z")doğru şeyi yapabilir ve doğru olanı alabilirsiniz, özellikle de Java'nın en son sürümleriyle Instantkırık yerine kullanmanız gerektiğinden java.util.Date.

Bunun DateTimeFormatteryerine de kullanmalısınız SimpleDateFormatter.

Orijinal Yanıt:

Aşağıdaki açıklama formatın temsil ettiği şekliyle hala geçerlidir. Ancak Java 8 her yerde bulunmadan önce yazılmıştır, bu nedenle Java 8 veya daha üstünü kullanıyorsanız kullanmamanız gereken eski sınıfları kullanır.

Bu Z, gösterildiği gibi sondaki girdiyle çalışır :

Desende her iki tarafından da Tkaçar '.

Sonundaki desen Zaslında XXXJavaDoc için belgelendiği gibi SimpleDateFormat, aslında nasıl kullanılacağı konusunda çok açık değil, çünkü Zeski TimeZonebilgilerin de işareti .

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

Aşağıdaki çıktıyı üretir:

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.InstantUTC'de bir anı temsil eden standart ISO 8601 biçimindeki metni ayrıştırmak için sınıfı kullanın .

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

ISO 8601

Bu biçim, tarih-saat dizesi biçimleri için ISO 8601 standardı tarafından tanımlanır .

Her ikisi de:

… Dizeleri ayrıştırmak ve oluşturmak için varsayılan olarak ISO 8601 formatlarını kullanın.

Genelde eski java.util.Date /.Calendar & java.text.SimpleDateFormat sınıflarını kötü niyetli, kafa karıştırıcı ve kusurlu oldukları için kullanmaktan kaçınmalısınız . Birlikte çalışma için gerekirse, ileri geri dönebilirsiniz.

java.time

Java 8 ve sonraki sürümlerinde yerleşik olan yeni java.time çerçevesi. Esinlenerek Joda-Time , tarafından tanımlanan JSR 310 ve uzatıldı ThreeTen-Ekstra proje.

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

Eski sınıfa dönüştürün.

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

Saat dilimi

Gerekirse, bir saat dilimi atayabilirsiniz.

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.

Dönüştürmek.

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

Joda-Time

GÜNCELLEME: Joda-Time projesi şimdi bakım modunda. Ekip, java.time sınıflarına geçişi önerir .

İşte Joda-Time 2.8'deki bazı örnek kod.

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.

Eski sınıfa dönüştürün. JuDate'e bir saat dilimi atanamadığından, atanan saat diliminin dönüşümde kaybolduğunu unutmayın.

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

Saat dilimi

Gerekirse, bir saat dilimi atayabilirsiniz.

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

Java'da hem modern hem de eski tarih-saat türleri tablosu.


Hakkında java.time

Java.time çerçevesi daha sonra Java 8 ve yerleşiktir. Bu sınıflar zahmetli eski yerini mirası gibi tarih-saat sınıfları java.util.Date, Calendar& SimpleDateFormat.

Artık bakım modunda olan Joda-Time projesi java.time sınıflarına geçişi tavsiye ediyor .

Daha fazla bilgi için Oracle Eğiticisine bakın . Ve birçok örnek ve açıklama için Stack Overflow'da arama yapın. Spesifikasyon JSR 310'dur .

Sen değiştirebilir java.time sizin veritabanı ile doğrudan nesneleri. JDBC 4.2 veya sonraki bir sürümüyle uyumlu bir JDBC sürücüsü kullanın . Dizeye gerek yok, sınıflara gerek yok .java.sql.*

Java.time sınıflarını nereden edinebilirsiniz?

Hangi Java veya Android sürümü ile kullanılacak java.time kütüphanesi tablosu.

ThreeTen-Ekstra proje ek sınıfları ile java.time uzanır. Bu proje, java.time'a gelecekteki olası eklemeler için bir kanıt zeminidir. Burada bazı yararlı sınıfları gibi bulabilir Interval, YearWeek, YearQuarter, ve daha .


1
@AalapPatel Joda-Time projesinin artık bakım modunda olduğunu unutmayın. Ekip, java.time sınıflarına geçişi önerir. Her iki çaba da aynı adam Stephen Colebourne tarafından yönetiliyor.
Basil Bourque

Teşekkür ederim, ben sunucu döndürülen UTC saat ve / veya yerel saat milisaniye almak için kullanın ve bu durumda benim için iyi çalışıyor ..
Aalap Patel

Instant.parse Android'de min api seviye 26 gerekiyor
Naveed Ahmad

1
@NaveedAhmad Yanıtın altındaki ThreeTen-Backport ve ThreeTenABP projeleri hakkındaki madde işaretlerine bakın .
Basil Bourque

0

Şimdiye kadar iki cevap var ve her ikisi de uzun (ve tl; dr çok kısa IMHO), bu yüzden yeni java.time kütüphanesini kullanmaya başlayan deneyimimden özet yazıyorum (Java sürümüne diğer cevaplarda da belirtildiği gibi) 8+). ISO 8601YYYY-MM-DD , tarih yazmak için standart bir yol belirler: bu nedenle tarih-saat biçimi yalnızca aşağıdaki gibidir (milisaniye için 0, 3, 6 veya 9 basamak olabilir) ve biçimlendirme dizesi gerekmez:

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

İhtiyacım yoktu, ancak yıl sorudan kodda olduğu için, o zaman:
daha zor, Instantdoğrudan yapılamıyor Calendar, sorular yoluyla yapılabilir Java ve Converting java'da mevcut yılın tamsayı değerini alın . Takvim zamanı ancak biçim sabit olduğu için IMHO alt dizeyi kullanmak daha kolaydır:

myDate.toString().substring(0,4);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.