ISO 8601 uyumlu Dize'yi java.util.Date'e dönüştürme


668

Bir ISO 8601 biçimli String dönüştürmek çalışıyorum java.util.Date.

yyyy-MM-dd'T'HH:mm:ssZBir Yerel Ayarla kullanılırsa (örneği karşılaştır) deseni ISO8601 uyumlu buldum .

Ancak, kullanarak java.text.SimpleDateFormatdoğru biçimlendirilmiş dize dönüştüremiyorum 2010-01-01T12:00:00+01:00. İlk önce 2010-01-01T12:00:00+0100iki nokta üst üste işaretine dönüştürmek zorundayım .

Yani, mevcut çözüm

SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.GERMANY);
String date = "2010-01-01T12:00:00+01:00".replaceAll("\\+0([0-9]){1}\\:00", "+0$100");
System.out.println(ISO8601DATEFORMAT.parse(date));

ki bu hiç hoş değil. Bir şey mi eksik veya daha iyi bir çözüm var mı?


Cevap

JuanZe'nin yorumu sayesinde, Joda-Time büyüsünü buldum, burada da açıklanıyor .

Yani, çözüm

DateTimeFormatter parser2 = ISODateTimeFormat.dateTimeNoMillis();
String jtdate = "2010-01-01T12:00:00+01:00";
System.out.println(parser2.parseDateTime(jtdate));

Veya daha basit bir şekilde, yapıcı aracılığıyla varsayılan ayrıştırıcıyı kullanın:

DateTime dt = new DateTime( "2010-01-01T12:00:00+01:00" ) ;

Benim için bu güzel.


243
Çok sayıda "JodaTime Kullan" yanıtı almaya hazır olun ...
JuanZe

3
@ Ice09: DateTimeFormat için API belgeleri doğruysa (JoDa belgeleri yanıltıcı, yanlış veya eksik olabilir), kendi "yanıtınızda" kullandığınız kalıp ISO8601 ile uyumlu değildir.
jarnbjo

21
Bunun ne zaman eklendiğinden emin değilim, ancak 'X' bu sorunu SimpleDateFormat içinde çözmek için görünüyor. "Yyyy-AA-gg'T'HH: dd: ssX" kalıbı sorudaki örneği başarıyla ayrıştırır.
mlohbihler

12
'X', Java 7'den beri kullanılabilir.
Lars Grammel

3
Java 8 bunu kolaylaştırıyor! Aşağıdaki cevaplarda Adam tarafından gizli bir mücevher var: stackoverflow.com/a/27479533/1262901
Fabian Keller

Yanıtlar:


477

Ne yazık ki, SimpleDateFormat (Java 6 ve öncesi) tarafından kullanılabilen saat dilimi biçimleri ISO 8601 uyumlu değildir . SimpleDateFormat, RFC # 822'ye göre "GMT + 01: 00" veya "+0100" gibi saat dilimi dizelerini anlar .

Java 7, ISO 8601'e göre saat dilimi tanımlayıcıları için destek eklemiş olsa bile, SimpleDateFormat, isteğe bağlı parçalar için desteği olmadığı için tam bir tarih dizesini düzgün bir şekilde ayrıştıramaz.

Regexp kullanarak giriş dizenizi yeniden biçimlendirmek kesinlikle bir olasılıktır, ancak değiştirme kuralları sorunuzdaki kadar basit değildir:

  • Bazı saat dilimleri UTC dışında tam saat değildir , bu nedenle dize mutlaka ": 00" ile bitmez.
  • ISO8601 yalnızca saat dilimine dahil edilecek saat sayısına izin verir, bu nedenle "+01", "+01: 00" değerine eşittir
  • ISO8601, "+00: 00" yerine UTC'yi belirtmek için "Z" kullanılmasına izin verir.

Daha kolay çözüm, JAXB'deki veri türü dönüştürücüsünü kullanmaktır, çünkü JAXB, XML Şeması belirtimine göre ISO8601 tarih dizesini ayrıştırabilmelidir. javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z")size bir Calendarnesne verir ve bir Datenesneye ihtiyacınız varsa getTime () yöntemini kullanabilirsiniz .

Muhtemelen Joda-Time'ı da kullanabilirsiniz , ama neden bununla uğraşman gerektiğini bilmiyorum.


18
JAXB çözümü gerçekten yaratıcı bir yaklaşım! İyi çalışıyor, numunemle test ettim. Bununla birlikte, sorunla karşı karşıya kalan ve JodaTime'ı kullanmasına izin verilenler için, daha doğal hissettirdiği için bunu kullanmanızı tavsiye ederim. Ancak çözümünüz ek kitaplık gerektirmez (en azından Java 6 ile).
Ice09

36
Bunun tam tersi: Takvim c = GregorianCalendar.getInstance (); c.setTime (aDate); return javax.xml.bind.DatatypeConverter.printDateTime (c);
Alexander Ljungberg

4
Aslında jaxb datatypeConverter'ı başlatmak zorunda olduğunuz kadar basit değil. DataTypeConverterImpl dahili olarak yaptığım gibi DatatypeFactory kendimi kullanarak sona erdi. Ne baş ağrısı.
gtrak

3
@Simon: Hayır, zaman dilimleri elbette göz ardı edilmiyor. Yanlış bir şey yapıyor olmalısın. Birkaç karakterden fazlasını yazıp bize gerçekten ne yaptığınızı söylerseniz, birisi size ne olduğunu açıklayabilir.
jarnbjo

4
@jarnbjo Karşılaştığım ilk joda-time, 1.8 öncesi, java date sınıflarını tercih eden ilk ve tek kişisiniz. Joda-time'ı, özellikle bir iğrençlik olan standart api ile karşılaştırıldığında, kelimenin tam anlamıyla bir sevinç buluyorum.
NimChimpsky

245

Java 7 belgeleriyle kutsanan yol :

DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
String string1 = "2001-07-04T12:08:56.235-0700";
Date result1 = df1.parse(string1);

DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
String string2 = "2001-07-04T12:08:56.235-07:00";
Date result2 = df2.parse(string2);

Sen bölümünde daha fazla örnek bulabilirsiniz Örnekler de SimpleDateFormat javadoc .

UPD 02/13/2020: Bunu Java 8'de yapmanın tamamen yeni bir yolu var


7
Cevabınız MongoDB'nin ISODate'ini yerel tarihe dönüştürmeme yardımcı oldu. Saygılarımızla.
Blue Sky

9
@ b.long Java, bu tür ISO 8601 uyumlu formatlar için bir sabitten daha fazlasını ekledi. Java, bu tür biçimler için yerleşik varsayılan desteği içeren tarih-saat çalışması için yepyeni bir çerçeve aldı. Java.util.Date, .Calendar ve SimpleDateFormat sınıflarının yerini alan, Java 8'deki Joda-Time'dan esinlenen yeni java.timeçerçeveye bakın .
Basil Bourque

2
Bu, tarih biçimini önceden bilmeniz gerektiği anlamına gelmiyor mu? Ya kabul etmek zorundaysanız string1ve string2hangisini alacağınızı bilmiyorsanız.
Timmmm

16
'Z' tırnak içinde olmalı
kervin

7
@kervin Z tırnak işaretleri arasındaysa, formatlayıcı temsil edebileceği ofset dizelerinin tümünü değil, özellikle Z karakterini aramayacak mı? Görünüşe göre Z'den alıntı yapmak sadece tarih dizeleriniz UTC'de olsaydı tesadüfle işe yarardı.
spaaarky21

201

Tamam, bu soru zaten cevaplandı, ama yine de cevabımı bırakacağım. Birine yardımcı olabilir.

Android (API 7) için bir çözüm arıyordum .

  • Joda söz konusu değildi - çok büyük ve yavaş başlatmadan muzdarip. Ayrıca, bu özel amaç için büyük bir abartı gibi görünüyordu.
  • İlgili yanıtlar javax.xmlAndroid API 7'de çalışmaz.

Bu basit sınıfı hayata geçirdi. Bu kapsar sadece en yaygın formu (tam emin girdi olacağını olduğunuzda ISO 8601 dizeleri, ancak bu bazı durumlarda yeterli olacaktır bu formatta).

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * Helper class for handling a most common subset of ISO 8601 strings
 * (in the following format: "2008-03-01T13:00:00+01:00"). It supports
 * parsing the "Z" timezone, but many other less-used features are
 * missing.
 */
public final class ISO8601 {
    /** Transform Calendar to ISO 8601 string. */
    public static String fromCalendar(final Calendar calendar) {
        Date date = calendar.getTime();
        String formatted = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
            .format(date);
        return formatted.substring(0, 22) + ":" + formatted.substring(22);
    }

    /** Get current date and time formatted as ISO 8601 string. */
    public static String now() {
        return fromCalendar(GregorianCalendar.getInstance());
    }

    /** Transform ISO 8601 string to Calendar. */
    public static Calendar toCalendar(final String iso8601string)
            throws ParseException {
        Calendar calendar = GregorianCalendar.getInstance();
        String s = iso8601string.replace("Z", "+00:00");
        try {
            s = s.substring(0, 22) + s.substring(23);  // to get rid of the ":"
        } catch (IndexOutOfBoundsException e) {
            throw new ParseException("Invalid length", 0);
        }
        Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(s);
        calendar.setTime(date);
        return calendar;
    }
}

Performans notu: Android 2.1'de bir hatadan kaçınmak için her seferinde yeni SimpleDateFormat'ı başlatırım . Benim kadar şaşkınsanız, bu bilmeceye bakın . Diğer Java motorları için, örneği özel bir statik alanda önbelleğe alabilirsiniz (iş parçacığı güvenli olması için ThreadLocal kullanarak).


2
Belki de bu, kendi cevabı ile kendi başına bir soru haline getirilmeliydi?
Thorbear

5
Bu, cevabı ararken karşılaştığım ilk sayfaydı, bu yüzden uygun görünüyordu. Çoğu Java geliştiricisi için Android tam olarak Java değildir. Ancak, çoğu durumda, biri diğeriyle aynı şekilde çalışır, bu nedenle birçok Android geliştiricisi bunu ararken "java" kelimesini arayacaktır.
wrygiel

1
Bunun milisaniye çözünürlüğü hesaba katmadığını unutmayın. Bu eklemek kolaydır.
Sky Kelsey

6
i kesirli saniye için .SSS eklemek zorunda kaldı ama harika thx çalışıyor. Neden yapıyorsun s = s.substring(0, 22) + s.substring(23);- bu noktayı görmüyorum
Dori

1
input = input.replaceAll ("[Zz]", "+0000"); çok çalışacak ve alt dize işleminden kaçınılabilir.
Javanator

115

java.time

Java.time API (daha sonra Java 8 ve yerleşik), biraz daha kolay bu hale getirir.

Girişin uçta (Zulu için) gibi UTC'de olduğunu biliyorsanız Z, Instantsınıf ayrıştırılabilir.

java.util.Date date = Date.from( Instant.parse( "2014-12-12T10:39:40Z" ));

Girişiniz, sonunda (Zulu) tarafından belirtilen UTC yerine UTC'den başka bir ofset değeri olabilirse , ayrıştırmak için sınıfı kullanın.ZOffsetDateTime

OffsetDateTime odt = OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" );

Sonra bir ayıklayın Instantve bir java.util.Dateçağırarak dönüştürün from.

Instant instant = odt.toInstant();  // Instant is always in UTC.
java.util.Date date = java.util.Date.from( instant );

8
Bu cevap çok çalışıyor. Bir java.util.Date tanımına göre saat dilimi yoktur. Yani tüm zaman dilimiyle ilgili koda gerek yok: LocalDateTimeve ZoneIdve atZone. Bu basit bir astar şunları yapacak:java.util.Date date = Date.from( ZonedDateTime.parse( "2014-12-12T10:39:40Z" ).toInstant() );
Basil Bourque

5
@BasilBourque Bu gereksiz yere karmaşık: Date.from(Instant.parse("2014-12-12T10:39:40Z" ));yeterlidir.
assylias

3
@assylias haklısınız, ancak bu yalnızca tarih dizesi UTC bölgesi olduğunda çalışır, ISO8601 herhangi bir saat dilimine izin verir ...
Adam

2
@ Adamım Kötüüm - sorunun örneğinizden daha genel olduğunu fark etmemiştim. Bir yan yorum olarak, OffsetDateTimeISO8601'i ayrıştırmak için yeterli olacaktır (saat dilimi bilgilerini içermez, sadece bir ofset içerir).
assylias

1
@assylias Ayrıştırma işlemine izin verme hakkındaki yorumunuz için teşekkür ederiz Instant. Bu soru için yeterli olmasa da, belirtilmesi gereken önemli bir ayrımdır. Bu yüzden ikinci bir kod örneği ekledim. Üzgünüz, bunun aslında benim cevabım olmadığını fark ettim; Umarım Adam onaylar.
Basil Bourque

67

Jackson-databind kütüphane de vardır ISO8601DateFormat sınıfını o (gerçek uygulama yapar ISO8601Utils .

ISO8601DateFormat df = new ISO8601DateFormat();
Date d = df.parse("2010-07-28T22:25:51Z");

Bu tarih ayrıştırmak başarısız: 2015-08-11T13:10:00. Anladım String index out of range: 19. Koda bakıldığında, milisaniye ve saat dilimi belirtilmesi gerekiyor gibi görünüyor. Bunlar isteğe bağlı olmalıdır.
Timmmm

2
Belgeleri alıntı, ayrıştırma biçimi şöyledir: [yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh:mm]]. Başka bir deyişle, milisaniye isteğe bağlıdır, ancak saat dilimi zorunludur.
david_p

2
Ah evet aslında haklısın. Yine de, ISO8601'in saat dilimini atlamanıza izin verdiğinden eminim, bu yüzden hala yanlış. JodaTime yine de çalışıyor:new DateTime("2015-08-11T13:10:00").toDate()
Timmmm

3
Bu sınıf artık kullanımdan kaldırıldı, yeni sınıf StdDateFormat. Aksi takdirde aynı şekilde çalışır.
JohnEye

51

tl; Dr.

OffsetDateTime.parse ( "2010-01-01T12:00:00+01:00" )

Java.time kullanma

Java 8 ve sonraki sürümlerindeki yeni java.time paketi Joda-Time'dan ilham aldı.

OffsetDateTimeSınıfı, bir ile zaman çizelgesinde bir anı temsil den-UTC-offset ancak bir zaman diliminde.

OffsetDateTime odt = OffsetDateTime.parse ( "2010-01-01T12:00:00+01:00" );

Arama toString, standart ISO 8601 biçiminde bir dize oluşturur:

2010-01-01T12: 00 + 01: 00

UTC merceğinden aynı değeri görmek için, bir ayıklamak Instantveya mahsup ayarlamak +01:00için 00:00.

Instant instant = odt.toInstant();  

…veya…

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

İsterseniz bir saat dilimine ayarlayın. Bir saat dilimi tarihidir ofset-den-UTC böyle Yaz Saati (DST) olarak anomaliler önlemek amacıyla kurallar kümesi ile, bir bölge için değerler. Bu nedenle, mümkünse yalnızca ofset yerine bir saat dilimi uygulayın.

ZonedDateTime zonedDateTimeMontréal = odt.atZoneSameInstant( ZoneId.of( "America/Montreal" ) );

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'a geçişi tavsiye ediyor sınıflarına .

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. Özellikler JSR 310 .

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?

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 .



27

Java sürüm 7 için

Oracle belgelerini takip edebilirsiniz: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

X - ISO 8601 zaman dilimi için kullanılır

TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());

System.out.println(nowAsISO);

DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
//nowAsISO = "2013-05-31T00:00:00Z";
Date finalResult = df1.parse(nowAsISO);

System.out.println(finalResult);

Bu, saat diliminin gerekli olduğu anlamına gelir . ISO 8601'e göre isteğe bağlıdır. Saniyede olduğu gibi vs. Bu sadece ISO
8601'in

1
Java 1.8 ile harika çalışıyor
Thiago Pereira

20

DatatypeConverter çözümü tüm VM'lerde çalışmaz. Aşağıdakiler benim için çalışıyor:

javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar("2011-01-01Z").toGregorianCalendar().getTime()

Joda'nın kutudan çıkmadığını gördüm (özellikle geçerli olması gereken bir tarihte saat dilimiyle yukarıda verdiğim örnek için)


15

Bence kullanmalıyız

DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")

Tarih için 2010-01-01T12:00:00Z


5
Neden 76 upvotes ile kabul edilen cevap dahil diğerlerinden daha iyi bir cevap?
Erick Robertson

3
@ErickRobertson: Basit, kutunun dışında, esnek, dönüşüm yok ve çoğu insan saat dilimlerini umursamıyor.
TWiStErRob

7
Zaman dilimlerini umursamıyorum zaman ile çalışma çok nokta!
Dori

16
Bu göz ardı tamamen dilimini. Bunun olduğunu anlayana kadar bunu kullanıyordum, bu yüzden JodaTime'a geçtim.
Joshua Pinter

3
Saat dilimini atmak bir noktada hatalara neden olacaktır.
Bart van Kuik

11

Java 8'den başlayarak, bunu yapmanın resmi olarak desteklenen tamamen yeni bir yolu var:

    String s = "2020-02-13T18:51:09.840Z";
    TemporalAccessor ta = DateTimeFormatter.ISO_INSTANT.parse(s);
    Instant i = Instant.from(ta);
    Date d = Date.from(i);

2
Dize anlık biçimdeyse Zve öteleme ofset olarak ise, bunu açıkça belirtmemiz gerekmez. Sadece Instant i = Instant.parse(s);. Sorudaki dize vardı +01:00, bu durumda DateTimeFormatter.ISO_INSTANTçalışmaz (en azından benim Java 11'de değil).
Ole VV

2
@ OleV.V. ISO_OFFSET_DATE_TIMETarihleri, ofsetlerle biçimlendirmek için kullanabilirsiniz +01:00( docs.oracle.com/javase/8/docs/api/java/time/format/… )
Lucas Basquerotto

1
Bu doğru, @LucasBasquerotto. Bu formatlayıcıdan açıkça bahsetmese de, Adam ve Basil Bourque tarafından verilen cevaplar zaten benzer bir şey yapıyor.
Ole VV

10

ISO8601 zaman damgalarını ayrıştırmanın başka bir basit yolu kullanmaktır org.apache.commons.lang.time.DateUtils:

import static org.junit.Assert.assertEquals;

import java.text.ParseException;
import java.util.Date;
import org.apache.commons.lang.time.DateUtils;
import org.junit.Test;

public class ISO8601TimestampFormatTest {
  @Test
  public void parse() throws ParseException {
    Date date = DateUtils.parseDate("2010-01-01T12:00:00+01:00", new String[]{ "yyyy-MM-dd'T'HH:mm:ssZZ" });
    assertEquals("Fri Jan 01 12:00:00 CET 2010", date.toString());
  }
}

6

java.time

Java 8'de java.time.ZonedDateTime sınıfını ve statik parse(CharSequence text)yöntemini kullanabileceğinizi unutmayın.


Soru'daki giriş dizelerinde tam saat dilimi değil, yalnızca UTC'den bir uzaklık vardır. Yani Instantve ZonedDateTimevardır, burada yok mülk ZonedDateTime.
Basil Bourque

6

Java 7+ için geçici çözüm SimpleDateFormat kullanıyor:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);

Bu kod ISO8601 biçimini aşağıdaki gibi ayrıştırabilir:

  • 2017-05-17T06:01:43.785Z
  • 2017-05-13T02:58:21.391+01:00

Ancak Java6'da karakteri SimpleDateFormatanlamıyor Xve
IllegalArgumentException: Unknown pattern character 'X'
atıyor ISO8601 tarihini Java 6 ile okunabilir biçime normalleştirmemiz gerekiyor SimpleDateFormat.

public static Date iso8601Format(String formattedDate) throws ParseException {
    try {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);
        return df.parse(formattedDate);
    } catch (IllegalArgumentException ex) {
        // error happen in Java 6: Unknown pattern character 'X'
        if (formattedDate.endsWith("Z")) formattedDate = formattedDate.replace("Z", "+0000");
        else formattedDate = formattedDate.replaceAll("([+-]\\d\\d):(\\d\\d)\\s*$", "$1$2");
        DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
        return df1.parse(formattedDate);
    }
}

Java 6'da hata oluştuğunda [ Zile +0000] veya [ +01:00ile +0100] değiştirme yöntemi (Java sürümünü algılayabilir ve try / catch komutunu if ifadesiyle değiştirebilirsiniz).


Hayır, gibi zahmetli eski tarih-saat sınıfları Dateve SimpleDateFormatkötü kafa karıştırıcı, tasarlanmış ve kusurlusun. Şimdi mirası var, Java 8 ve sonraki sürümlerinde yerleşik java.time sınıflarıyla destekleniyorlar. Java 6 ve Java 7 için, java.time işlevselliğinin çoğu ThreeTen-Backport projesinde geriye taşınır . Bu kütüphaneyi uygulamanıza eklemek, bu eski sınıfları kullanmaktan çok daha iyidir. Java.time'da tek satırlık çözüm:OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" )
Basil Bourque

5

Aynı sorunla karşılaştım ve aşağıdaki kodla çözdüm.

 public static Calendar getCalendarFromISO(String datestring) {
    Calendar calendar = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault()) ;
    SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
    try {
        Date date = dateformat.parse(datestring);
        date.setHours(date.getHours() - 1);
        calendar.setTime(date);

        String test = dateformat.format(calendar.getTime());
        Log.e("TEST_TIME", test);

    } catch (ParseException e) {
        e.printStackTrace();
    }

    return calendar;
}

Daha önce kullanıyordum SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());

Ama daha sonra istisnanın ana nedenini buldum yyyy-MM-dd'T'HH:mm:ss.SSSZ,

Ben de kullandım

SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());

Benim için iyi çalıştı .


Joda-time, XML api ya da başka bir şey kullanmak zorunda kalmadan ihtiyacım olan şey. Sadece doğru desen.
Philippe Gioseffi


4

Burada mükemmel cevapların gösterdiği gibi Java'nın bir tarih-saatini ayrıştırmak için bir düzine farklı yolu vardır. Ama şaşırtıcı bir şekilde, Java'nın zaman sınıflarından hiçbiri ISO 8601'i tam olarak uygulamıyor!

Java 8 ile şunları öneririm:

ZonedDateTime zp = ZonedDateTime.parse(string);
Date date = Date.from(zp.toInstant());

Bu, hem UTC'de hem de "2017-09-13T10: 36: 40Z" veya "2017-09-13T10: 36: 40 + 01: 00" gibi bir ofsetle örnekleri işleyecektir. Çoğu kullanım durumunda yapılacaktır.

Ama böyle örnekler ele olmayacak "2017-09-13T10: 36: 40 + 01", hangi olan geçerli bir ISO 8601 tarih-saat.
Ayrıca yalnızca tarihi işlemez, örneğin "2017-09-13".

Bunlarla başa çıkmak zorunda kalırsanız, sözdizimini koklamak için önce bir regex kullanmanızı öneririm.

Burada çok sayıda köşe vakası olan ISO 8601 örneklerinin güzel bir listesi var: https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/ I'm hepsiyle baş edebilecek herhangi bir Java sınıfının farkında değil.


OffsetDateTimetarih-saatini bir ofset ile daha iyi yapar ve kavramsal olarak eşleştirir.
Ole VV

Hey @ OleV.V. Önerin için teşekkürler. Ne yazık ki hayır: OffsetDateTime.parse () birkaç geçerli ISO 8601 dizesi için bir istisna atar, örneğin "2017-09-13T10: 36: 40 + 01" veya "2017-09-13"
Daniel Winterstein

Sadece bununla OffsetDateTimeuğraştığın örnekleri ele aldığını söylemek istedim ZonedDateTime. İnanmayan örneklerin hiçbirini ele almadığına inanıyorum ZonedDateTime. Bu anlamda bir gelişme yok (aynı zamanda daha da kötüsü değil). Üzgünüm, tam olarak net değildim.
Ole VV

1
Durumlar göz önüne alındığında, bu 2020'de kabul edilen cevap olmalıdır.
slashCoder


3

Diğerlerinin de belirttiği gibi Android, SDK'da bulunan sınıfları kullanarak ISO 8601 tarihlerini ayrıştırmayı / biçimlendirmeyi desteklemenin iyi bir yoluna sahip değil. Nihayet biçimlendirme ve ISO 8601 ve RFC 1123 tarihlerini ayrıştırma destekleyen bir DateUtils sınıfı içeren bir Gist oluşturdu bu kodu birden çok kez yazdım. Gist ayrıca neyi desteklediğini gösteren bir test durumu içerir.

https://gist.github.com/mraccola/702330625fad8eebe7d3


2

JAVA 1.7 için SimpleDateFormat, ISO 8601 formatı için harika bir desene sahiptir.

Sınıf SimpleDateFormat

İşte yaptığım şey:

Date d = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
         Locale.ENGLISH).format(System.currentTimeMillis());

2
Zbiçim dizesinde ISO 8601 saat dilimi değil, ISO 8601 saat dilimi istiyorsanız X(veya XXveya XXX) kullanmalısınız
Vojta

d String
Tim Child

1

Şöyle yapın:

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

    String dateStr = "2016-10-19T14:15:36+08:00";
    Date date = javax.xml.bind.DatatypeConverter.parseDateTime(dateStr).getTime();

    System.out.println(date);

}

İşte çıktı:

Çar 19 Eki 15:15:36 CST 2016


1

Gibi dize kullan LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)


1

Https://en.wikipedia.org/wiki/ISO_8601 uyarınca bir java kütüphanesinin bile tüm ISO 8601 tarih biçimlerini desteklemediğine şaşırdım . Joda DateTime bunların çoğunu destekliyordu, ama hepsini desteklemedi ve bu yüzden hepsini işlemek için özel mantık ekledim. İşte benim uygulama.

import java.text.ParseException;
import java.util.Date;

import org.apache.commons.lang3.time.DateUtils;
import org.joda.time.DateTime;

public class ISO8601DateUtils {
	
	/**
	 * It parses all the date time formats from https://en.wikipedia.org/wiki/ISO_8601 and returns Joda DateTime.
	 * Zoda DateTime does not support dates of format 20190531T160233Z, and hence added custom logic to handle this using SimpleDateFormat.
	 * @param dateTimeString ISO 8601 date time string
	 * @return
	 */
	public static DateTime parse(String dateTimeString) {
		try {
			return new DateTime( dateTimeString );
		} catch(Exception e) {
			try {
				Date dateTime = DateUtils.parseDate(dateTimeString, JODA_NOT_SUPPORTED_ISO_DATES);
				return new DateTime(dateTime.getTime());
			} catch (ParseException e1) {
				throw new RuntimeException(String.format("Date %s could not be parsed to ISO date", dateTimeString));
			}
		}
	}
  
  	private static String[] JODA_NOT_SUPPORTED_ISO_DATES = new String[] {
			// upto millis
			"yyyyMMdd'T'HHmmssSSS'Z'",
			"yyyyMMdd'T'HHmmssSSSZ",
			"yyyyMMdd'T'HHmmssSSSXXX",
			
			"yyyy-MM-dd'T'HHmmssSSS'Z'",
			"yyyy-MM-dd'T'HHmmssSSSZ",
			"yyyy-MM-dd'T'HHmmssSSSXXX",
			
			// upto seconds
			"yyyyMMdd'T'HHmmss'Z'",
			"yyyyMMdd'T'HHmmssZ",
			"yyyyMMdd'T'HHmmssXXX",
			
			"yyyy-MM-dd'T'HHmmss'Z'", 
			"yyyy-MM-dd'T'HHmmssZ",
			"yyyy-MM-dd'T'HHmmssXXX",
			
			// upto minutes
			"yyyyMMdd'T'HHmm'Z'",
			"yyyyMMdd'T'HHmmZ",
			"yyyyMMdd'T'HHmmXXX",

			"yyyy-MM-dd'T'HHmm'Z'",
			"yyyy-MM-dd'T'HHmmZ",
			"yyyy-MM-dd'T'HHmmXXX",
			
			//upto hours is already supported by Joda DateTime
	};
}


1

ISO8601'de bir tarihin nasıl ayrıştırılacağını ve LocalDateTime'ın DST'leri işlemediğini gösteren küçük bir test.

 @Test
    public void shouldHandleDaylightSavingTimes() throws ParseException {

        //ISO8601 UTC date format
        SimpleDateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");

        // 1 hour of difference between 2 dates in UTC happening at the Daylight Saving Time
        Date d1 = utcFormat.parse("2019-10-27T00:30:00.000Z");
        Date d2 = utcFormat.parse("2019-10-27T01:30:00.000Z");

        //Date 2 is before date 2
        Assert.assertTrue(d1.getTime() < d2.getTime());
        // And there is 1 hour difference between the 2 dates
        Assert.assertEquals(1000*60*60, d2.getTime() - d1.getTime());

        //Print the dates in local time
        SimpleDateFormat localFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm z Z", Locale.forLanguageTag("fr_CH"));
        localFormat.setTimeZone(TimeZone.getTimeZone("Europe/Zurich"));

        //Both dates are at 02h30 local time (because of DST), but one is CEST +0200 and the other CET +0100 (clock goes backwards)
        Assert.assertEquals("2019-10-27 02:30 CEST +0200", localFormat.format(d1));
        Assert.assertEquals("2019-10-27 02:30 CET +0100", localFormat.format(d2));

        //Small test that shows that LocalDateTime does not handle DST (and should not be used for storing timeseries data)
        LocalDateTime ld1 = LocalDateTime.ofInstant(d1.toInstant(), ZoneId.of("Europe/Zurich"));
        LocalDateTime ld2 = LocalDateTime.ofInstant(d2.toInstant(), ZoneId.of("Europe/Zurich"));

        //Note that a localdatetime does not handle DST, therefore the 2 dates are the same
        Assert.assertEquals(ld1, ld2);

        //They both have the following local values
        Assert.assertEquals(2019, ld1.getYear());
        Assert.assertEquals(27, ld1.getDayOfMonth());
        Assert.assertEquals(10, ld1.getMonthValue());
        Assert.assertEquals(2, ld1.getHour());
        Assert.assertEquals(30, ld1.getMinute());
        Assert.assertEquals(0, ld1.getSecond());

    }

3
Bilginize gibi korkunç zahmetli tarih-saat sınıfları java.util.Date, java.util.Calendarve java.text.SimpleDateFormatşimdi mirası supplanted, java.time sonra Java 8 ve yerleşik sınıflara. Oracle'ın Öğreticisine bakın .
Basil Bourque

Bunu doğru LocalDateTimeo hiç bir zaman dilimini ele olmadığından yaz saati (DST) işlemez. Bunun için ihtiyacımız var ZonedDateTime. Önermek Dateve SimpleDateFormat- IMHO kötü.
Ole VV

1
Gerçekten ZonedDateTime çalışır. Ve java.time Anında DST ile başa çıkmak için iyi bir alternatiftir. Java.util.Date kullanımdan kaldırıldığını ve kullanılmaması gerektiğini biliyorum, ama sadece orijinal soruyu cevaplıyordum:
8601'de

0

Benzer bir ihtiyacım vardı: ISO8601 uyumlu herhangi bir tarihi önceden kesin formatı bilmeden ayrıştırabilmem gerekiyordu ve Android'de de çalışacak hafif bir çözüm istedim.

İhtiyaçlarımı araştırdığımda bu soruya tökezledim ve AFAIU'nun hiçbir cevabımın ihtiyaçlarıma tamamen uymadığını fark ettim. Bu yüzden jISO8601'i geliştirdim ve maven merkezine ittim.

Sadece ekleyin pom.xml:

<dependency>
  <groupId>fr.turri</groupId>
  <artifactId>jISO8601</artifactId>
  <version>0.2</version>
</dependency>

ve sonra gitmekte fayda var:

import fr.turri.jiso8601.*;
...
Calendar cal = Iso8601Deserializer.toCalendar("1985-03-04");
Date date = Iso8601Deserializer.toDate("1985-03-04T12:34:56Z");

Umarım yardımcı olur.



-1

Temel İşlev Nezaket: @wrygiel.

Bu işlev, ofset değerlerini işleyebilen ISO8601 biçimini Java Tarihine dönüştürebilir. Gereğince ISO 8601 tanımına ofset farklı biçimlerde söz edilebilir.

±[hh]:[mm]
±[hh][mm]
±[hh]

Eg:  "18:30Z", "22:30+04", "1130-0700", and "15:00-03:30" all mean the same time. - 06:30PM UTC

Bu sınıfın dönüştürmek için statik yöntemleri var

  • ISO8601 dizeden Date (Yerel Saat Dilimi) nesnesine
  • ISO8601 dizesine tarih
  • Yaz Saati Uygulaması otomatik olarak kireçlenir

Örnek ISO8601 Dizeleri

/*       "2013-06-25T14:00:00Z";
         "2013-06-25T140000Z";
         "2013-06-25T14:00:00+04";
         "2013-06-25T14:00:00+0400";
         "2013-06-25T140000+0400";
         "2013-06-25T14:00:00-04";
         "2013-06-25T14:00:00-0400";
         "2013-06-25T140000-0400";*/


public class ISO8601DateFormatter {

private static final DateFormat DATE_FORMAT_1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
private static final DateFormat DATE_FORMAT_2 = new SimpleDateFormat("yyyy-MM-dd'T'HHmmssZ");
private static final String UTC_PLUS = "+";
private static final String UTC_MINUS = "-";

public static Date toDate(String iso8601string) throws ParseException {
    iso8601string = iso8601string.trim();
    if(iso8601string.toUpperCase().indexOf("Z")>0){
        iso8601string = iso8601string.toUpperCase().replace("Z", "+0000");
    }else if(((iso8601string.indexOf(UTC_PLUS))>0)){
        iso8601string = replaceColon(iso8601string, iso8601string.indexOf(UTC_PLUS));
        iso8601string = appendZeros(iso8601string, iso8601string.indexOf(UTC_PLUS), UTC_PLUS);
    }else if(((iso8601string.indexOf(UTC_MINUS))>0)){
        iso8601string = replaceColon(iso8601string, iso8601string.indexOf(UTC_MINUS));
        iso8601string = appendZeros(iso8601string, iso8601string.indexOf(UTC_MINUS), UTC_MINUS);
    }

    Date date = null;
    if(iso8601string.contains(":"))
        date = DATE_FORMAT_1.parse(iso8601string);
    else{
        date = DATE_FORMAT_2.parse(iso8601string);
    }
    return date;
}

public static String toISO8601String(Date date){
    return DATE_FORMAT_1.format(date);
}

private static String replaceColon(String sourceStr, int offsetIndex){
    if(sourceStr.substring(offsetIndex).contains(":"))
        return sourceStr.substring(0, offsetIndex) + sourceStr.substring(offsetIndex).replace(":", "");
    return sourceStr;
}

private static String appendZeros(String sourceStr, int offsetIndex, String offsetChar){
    if((sourceStr.length()-1)-sourceStr.indexOf(offsetChar,offsetIndex)<=2)
        return sourceStr + "00";
    return sourceStr;
}

}


2
Dikkat edin - DateFormat ve türetilmiş sınıflar çok iş parçacıklı uyumlu değildir! DATE_FORMAT_1 ve DATE_FORMAT_2 gibi statik SimpleDateFormat nesnelerini kullanmak, ISO8601DateFormatter işlevlerini çağıran birden çok iş parçacığının aynı DateFormat nesnesini paylaşacağı anlamına gelir. Bu, veri bozulmasına ve DateFormat çağrılarından hatalı tarihlerin döndürülmesine yol açar. Bunu düzeltmek için, desen dizeleri sabitlerini yapmanız ve gerektiğinde yerel SimpleDateFormat değişkenleri oluşturmanız gerekir. Bu, her nesnenin sadece bir iş parçacığı tarafından kullanılmasını sağlar.
Theo

İş parçacığı güvenliği için daha iyi bir düzeltme, iş parçacığı güvenliği için oluşturulmuş bir tarih-saat kitaplığı kullanmaktır. Java'da bu dünya ya Joda-Time ya da java.time olur.
Basil Bourque

-1

Bu benim için en iyi sonuç verdi:

public static Date fromISO8601_( String string ) {

    try {
            return new SimpleDateFormat ( "yyyy-MM-dd'T'HH:mm:ssXXX").parse ( string );
    } catch ( ParseException e ) {
        return Exceptions.handle (Date.class, "Not a valid ISO8601", e);
    }


}

Java fro / fro JavaScript tarih dizeleri dönüştürmek gerekiyordu. Yukarıdaki çalışmaları tavsiye ile buldum. SimpleDateFormat kullanan yakın olan bazı örnekler vardı, ancak bunlar tarafından önerilen alt küme gibi görünmüyordu:

http://www.w3.org/TR/NOTE-datetime

ve PLIST ve JavaScript Dizeleri tarafından destekleniyor ve ihtiyacım olan şey bu.

Bu, ISO8601 dizesinin en yaygın biçimi ve iyi bir alt küme gibi görünüyor.

Verdikleri örnekler:

1994-11-05T08:15:30-05:00 corresponds 
November 5, 1994, 8:15:30 am, US Eastern Standard Time.

 1994-11-05T13:15:30Z corresponds to the same instant.

Ayrıca hızlı bir sürümü var:

final static int SHORT_ISO_8601_TIME_LENGTH =  "1994-11-05T08:15:30Z".length ();
                                            // 01234567890123456789012
final static int LONG_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30-05:00".length ();


public static Date fromISO8601( String string ) {
    if (isISO8601 ( string )) {
        char [] charArray = Reflection.toCharArray ( string );//uses unsafe or string.toCharArray if unsafe is not available
        int year = CharScanner.parseIntFromTo ( charArray, 0, 4 );
        int month = CharScanner.parseIntFromTo ( charArray, 5, 7 );
        int day = CharScanner.parseIntFromTo ( charArray, 8, 10 );
        int hour = CharScanner.parseIntFromTo ( charArray, 11, 13 );

        int minute = CharScanner.parseIntFromTo ( charArray, 14, 16 );

        int second = CharScanner.parseIntFromTo ( charArray, 17, 19 );

        TimeZone tz ;

         if (charArray[19] == 'Z') {

             tz = TimeZone.getTimeZone ( "GMT" );
         } else {

             StringBuilder builder = new StringBuilder ( 9 );
             builder.append ( "GMT" );
             builder.append( charArray, 19, LONG_ISO_8601_TIME_LENGTH - 19);
             String tzStr = builder.toString ();
             tz = TimeZone.getTimeZone ( tzStr ) ;

         }
         return toDate ( tz, year, month, day, hour, minute, second );

    }   else {
        return null;
    }

}

...

public static int parseIntFromTo ( char[] digitChars, int offset, int to ) {
    int num = digitChars[ offset ] - '0';
    if ( ++offset < to ) {
        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
        if ( ++offset < to ) {
            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
            if ( ++offset < to ) {
                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                if ( ++offset < to ) {
                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                    if ( ++offset < to ) {
                        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                        if ( ++offset < to ) {
                            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                            if ( ++offset < to ) {
                                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                if ( ++offset < to ) {
                                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return num;
}


public static boolean isISO8601( String string ) {
      boolean valid = true;

      if (string.length () == SHORT_ISO_8601_TIME_LENGTH) {
          valid &=  (string.charAt ( 19 )  == 'Z');

      } else if (string.length () == LONG_ISO_8601_TIME_LENGTH) {
          valid &=  (string.charAt ( 19 )  == '-' || string.charAt ( 19 )  == '+');
          valid &=  (string.charAt ( 22 )  == ':');

      } else {
          return false;
      }

    //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
    // "1 9 9 4 - 1 1 - 0 5 T 0 8 : 1 5 : 3 0 - 0 5 : 0 0

    valid &=  (string.charAt ( 4 )  == '-') &&
                (string.charAt ( 7 )  == '-') &&
                (string.charAt ( 10 ) == 'T') &&
                (string.charAt ( 13 ) == ':') &&
                (string.charAt ( 16 ) == ':');

    return valid;
}

Ben karşılaştırmak değil, ama sanırım oldukça hızlı olacak. İşe yarıyor gibi görünüyor. :)

@Test
public void testIsoShortDate() {
    String test =  "1994-11-05T08:15:30Z";

    Date date = Dates.fromISO8601 ( test );
    Date date2 = Dates.fromISO8601_ ( test );

    assertEquals(date2.toString (), date.toString ());

    puts (date);
}

@Test
public void testIsoLongDate() {
    String test =  "1994-11-05T08:11:22-05:00";

    Date date = Dates.fromISO8601 ( test );
    Date date2 = Dates.fromISO8601_ ( test );

    assertEquals(date2.toString (), date.toString ());

    puts (date);
}

-2

Bir çok insanın yapmak istediği şey JSON tarih dizelerini ayrıştırmak. Bu sayfaya gelirseniz, bir JavaScript JSON tarihini bir Java tarihine dönüştürmek isteyebilirsiniz.

JSON tarih dizesinin neye benzediğini göstermek için:

    var d=new Date();
    var s = JSON.stringify(d);

    document.write(s);
    document.write("<br />"+d);


    "2013-12-14T01:55:33.412Z"
    Fri Dec 13 2013 17:55:33 GMT-0800 (PST)

JSON tarih dizesi 2013-12-14T01: 55: 33.412Z'dir.

Tarihler JSON spesifikasyonları tarafından kapsanmamaktadır, ancak yukarıda belirtilenler çok özel bir ISO 8601 formatı iken, ISO_8601 çok daha büyüktür ve bu çok önemli olsa da sadece bir alt kümedir.

Bkz. Http://www.json.org Bkz. Http://en.wikipedia.org/wiki/ISO_8601 Bkz. Http://www.w3.org/TR/NOTE-datetime

Olduğu gibi, her ikisi de ISO-8601 kullanan ancak aynı bitleri olmayan bir JSON ayrıştırıcısı ve bir PLIST ayrıştırıcısı yazdım.

/*
    var d=new Date();
    var s = JSON.stringify(d);

    document.write(s);
    document.write("<br />"+d);


    "2013-12-14T01:55:33.412Z"
    Fri Dec 13 2013 17:55:33 GMT-0800 (PST)


 */
@Test
public void jsonJavaScriptDate() {
    String test =  "2013-12-14T01:55:33.412Z";

    Date date = Dates.fromJsonDate ( test );
    Date date2 = Dates.fromJsonDate_ ( test );

    assertEquals(date2.toString (), "" + date);

    puts (date);
}

Projem için bunu yapmanın iki yolunu yazdım. Bir standart, bir hızlı.

Yine, JSON tarih dizesi ISO 8601'in çok özel bir uygulamasıdır ....

(Diğerini farklı bir ISO 8601 formatı olan PLIST tarihleri ​​için çalışması gereken diğer cevapta yayınladım).

JSON tarihi aşağıdaki gibidir:

public static Date fromJsonDate_( String string ) {

    try {

        return new SimpleDateFormat ( "yyyy-MM-dd'T'HH:mm:ss.SSSXXX").parse ( string );
    } catch ( ParseException e ) {
        return Exceptions.handle (Date.class, "Not a valid JSON date", e);
    }


}

PLIST dosyaları (GNUNext olmayan ASCII) de ISO 8601 kullanıyor ancak milisaniye yok, bu yüzden ... ISO-8601 tarihlerinin hepsi aynı değil. (En azından henüz milis kullanan bir tane bulamadım ve gördüğüm ayrıştırıcı saat dilimini tamamen atlıyor OMG).

Şimdi hızlı sürüm için (Boon'da bulabilirsiniz).

public static Date fromJsonDate( String string ) {

    return fromJsonDate ( Reflection.toCharArray ( string ), 0, string.length () );

}

Reflection.toCharArray öğesinin kullanılabiliyorsa güvensiz kullandığını, ancak varsayılan olarak string.toCharArray öğesini kullandığını unutmayın.

(Reflection.toCharArray (string) öğesini string.toCharArray () ile değiştirerek örnekten çıkarabilirsiniz).

public static Date fromJsonDate( char[] charArray, int from, int to ) {

    if (isJsonDate ( charArray, from, to )) {
        int year = CharScanner.parseIntFromTo ( charArray, from + 0, from + 4 );
        int month = CharScanner.parseIntFromTo ( charArray,  from +5,  from +7 );
        int day = CharScanner.parseIntFromTo ( charArray,  from +8,  from +10 );
        int hour = CharScanner.parseIntFromTo ( charArray,  from +11,  from +13 );

        int minute = CharScanner.parseIntFromTo ( charArray,  from +14,  from +16 );

        int second = CharScanner.parseIntFromTo ( charArray,  from +17,  from +19 );

        int miliseconds = CharScanner.parseIntFromTo ( charArray,  from +20,  from +23 );

        TimeZone tz = TimeZone.getTimeZone ( "GMT" );


        return toDate ( tz, year, month, day, hour, minute, second, miliseconds );

    }   else {
        return null;
    }

}

İsJsonDate aşağıdaki gibi uygulanır:

public static boolean isJsonDate( char[] charArray, int start, int to ) {
    boolean valid = true;
    final int length = to -start;

    if (length != JSON_TIME_LENGTH) {
        return false;
    }

    valid &=  (charArray [ start + 19 ]  == '.');

    if (!valid) {
        return false;
    }


    valid &=  (charArray[  start +4 ]  == '-') &&
            (charArray[  start +7 ]  == '-') &&
            (charArray[  start +10 ] == 'T') &&
            (charArray[  start +13 ] == ':') &&
            (charArray[  start +16 ] == ':');

    return valid;
}

Her neyse ... Tahminimce buraya gelen birkaç kişi JSON Date String'i arıyor olabilir ve bir ISO-8601 tarihi olmasına rağmen, çok özel bir ayrıştırmaya ihtiyaç duyan çok özel bir tanesidir.

public static int parseIntFromTo ( char[] digitChars, int offset, int to ) {
    int num = digitChars[ offset ] - '0';
    if ( ++offset < to ) {
        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
        if ( ++offset < to ) {
            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
            if ( ++offset < to ) {
                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                if ( ++offset < to ) {
                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                    if ( ++offset < to ) {
                        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                        if ( ++offset < to ) {
                            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                            if ( ++offset < to ) {
                                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                if ( ++offset < to ) {
                                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return num;
}

Bkz. Https://github.com/RichardHightower/boon Boon'un bir PLIST ayrıştırıcısı (ASCII) ve bir JSON ayrıştırıcısı vardır.

JSON ayrıştırıcısı, bildiğim en hızlı Java JSON ayrıştırıcısıdır.

Gatling Performance dostları tarafından bağımsız olarak doğrulandı.

https://github.com/gatling/json-parsers-benchmark

Benchmark                               Mode Thr     Count  Sec         Mean   Mean error        Units
BoonCharArrayBenchmark.roundRobin      thrpt  16        10    1   724815,875    54339,825    ops/s
JacksonObjectBenchmark.roundRobin      thrpt  16        10    1   580014,875   145097,700    ops/s
JsonSmartBytesBenchmark.roundRobin     thrpt  16        10    1   575548,435    64202,618    ops/s
JsonSmartStringBenchmark.roundRobin    thrpt  16        10    1   541212,220    45144,815    ops/s
GSONStringBenchmark.roundRobin         thrpt  16        10    1   522947,175    65572,427    ops/s
BoonDirectBytesBenchmark.roundRobin    thrpt  16        10    1   521528,912    41366,197    ops/s
JacksonASTBenchmark.roundRobin         thrpt  16        10    1   512564,205   300704,545    ops/s
GSONReaderBenchmark.roundRobin         thrpt  16        10    1   446322,220    41327,496    ops/s
JsonSmartStreamBenchmark.roundRobin    thrpt  16        10    1   276399,298   130055,340    ops/s
JsonSmartReaderBenchmark.roundRobin    thrpt  16        10    1    86789,825    17690,031    ops/s

Akışlar, okuyucular, bayt [], char [], CharSequence (StringBuilder, CharacterBuffer) ve String için en hızlı JSON ayrıştırıcısına sahiptir.

Diğer ölçütlere bakın:

https://github.com/RichardHightower/json-parsers-benchmark


JSON ile ilgili bu cevap sorudan konu dışıdır. Ayrıca, çok az JSON veri türü arasında “JSON tarihi” diye bir şey olmadığından, bu Soru yanlıştır . Ve günümüzde, tüm bu kod yerleşik Java özelliği için tek hatlı bir çağrı ile değiştirilebilir:Instant.parse( "2013-12-14T01:55:33.412Z" )
Basil Bourque
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.