Konwertowanie łańcucha zgodnego z ISO 8601 na java.util.Date


668

Próbuję przekonwertować ciąg w formacie ISO 8601 na plik java.util.Date.

Stwierdziłem, że wzorzec yyyy-MM-dd'T'HH:mm:ssZjest zgodny z ISO8601, jeśli jest używany z ustawieniami regionalnymi (porównaj próbkę).

Jednak używając java.text.SimpleDateFormatnie mogę przekonwertować poprawnie sformatowanego ciągu 2010-01-01T12:00:00+01:00. Najpierw muszę go przekonwertować 2010-01-01T12:00:00+0100, bez dwukropka.

Tak więc obecne rozwiązanie to

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

co oczywiście nie jest takie miłe. Czy coś mi brakuje, czy jest lepsze rozwiązanie?


Odpowiedź

Dzięki komentarzowi JuanZe znalazłem magię Joda-Time , która jest tu również opisana .

Tak więc rozwiązaniem jest

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

Lub prościej, użyj domyślnego analizatora składni za pośrednictwem konstruktora:

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

Dla mnie to miłe.


243
Przygotuj się na otrzymywanie wielu odpowiedzi „Użyj JodaTime” ...
JuanZe

3
@ Ice09: Jeśli dokumentacja API dla DateTimeFormat jest poprawna (dokumentacja JoDa może być myląca, błędna lub niekompletna), wzorzec użyty we własnej „odpowiedzi” nie jest zgodny z ISO8601.
jarnbjo

21
Nie jestem pewien, kiedy to zostało dodane, ale „X” wydaje się rozwiązać ten problem w SimpleDateFormat. Wzór „rrrr-MM-dd'T'HG: mm: ssX” z powodzeniem analizuje przykład w pytaniu.
mlohbihler

12
„X” jest dostępny od Java 7.
Lars Grammel

3
Java 8 ułatwia! W odpowiedziach poniżej ukryty klejnot: stackoverflow.com/a/27479533/1262901
Fabian Keller

Odpowiedzi:


477

Niestety formaty stref czasowych dostępne dla SimpleDateFormat (Java 6 i wcześniejsze) nie są zgodne z ISO 8601 . SimpleDateFormat rozumie ciągi stref czasowych, takie jak „GMT + 01: 00” lub „+0100”, ten ostatni zgodnie z RFC # 822 .

Nawet jeśli Java 7 dodała obsługę deskryptorów stref czasowych zgodnie z ISO 8601, SimpleDateFormat nadal nie jest w stanie poprawnie przeanalizować pełnego ciągu daty, ponieważ nie obsługuje części opcjonalnych.

Ponowne formatowanie ciągu wejściowego za pomocą wyrażenia regularnego jest z pewnością jedną z możliwości, ale reguły zastępowania nie są tak proste jak w pytaniu:

  • Niektóre strefy czasowe nie są pełnymi godzinami wolnego czasu UTC , więc ciąg nie musi kończyć się na „: 00”.
  • ISO8601 pozwala na uwzględnienie tylko liczby godzin w strefie czasowej, więc „+01” jest równoważne z „+01: 00”
  • ISO8601 pozwala na użycie „Z” do wskazania UTC zamiast „+00: 00”.

Najłatwiejszym rozwiązaniem jest użycie konwertera typu danych w JAXB, ponieważ JAXB musi być w stanie przeanalizować ciąg daty ISO8601 zgodnie ze specyfikacją schematu XML. javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z")da ci Calendarobiekt i możesz po prostu użyć na nim getTime (), jeśli potrzebujesz Dateobiektu.

Prawdopodobnie mógłbyś również użyć Joda-Time , ale nie wiem, dlaczego miałbyś się tym przejmować.


18
Rozwiązanie JAXB to naprawdę kreatywne podejście! Działa również, przetestowałem to na mojej próbce. Jednak dla każdego, kto napotyka problem i może korzystać z JodaTime, radzę go używać, ponieważ wydaje się to bardziej naturalne. Ale twoje rozwiązanie nie wymaga dodatkowych bibliotek (przynajmniej z Javą 6).
Ice09

36
Oto odwrotność: Kalendarz c = GregorianCalendar.getInstance (); c.setTime (aDate); return javax.xml.bind.DatatypeConverter.printDateTime (c);
Alexander Ljungberg,

4
W rzeczywistości nie jest to tak proste, że trzeba zainicjować konwerter danych typu jaxb. Skończyło się na tym, że sam użyłem DatatypeFactory, jak DataTypeConverterImpl. Co za ból głowy.
gtrak

3
@ Simon: Nie, strefy czasowe oczywiście nie są ignorowane. Musisz robić coś złego. Jeśli wpiszesz więcej niż kilka znaków i powiesz nam, co naprawdę robisz, ktoś może ci wyjaśnić.
jarnbjo

4
@ jarnbjo jesteś pierwszą i jedyną osobą, z którą się spotkałem, która preferuje standardowe, datowe wersje java, przed czasem Joda. Czas joda jest dla mnie dosłowną radością, szczególnie w porównaniu ze standardowym API, które jest obrzydliwością.
NimChimpsky

245

Sposób, który jest błogosławiony przez dokumentację Java 7 :

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

Więcej przykładów można znaleźć w sekcji Przykłady na SimpleDateFormat javadoc .

UPD 02/13/2020: Istnieje zupełnie nowy sposób na zrobienie tego w Javie 8


7
Twoja odpowiedź pomogła mi przekonwertować ISODate MongoDB na lokalną datę. Pozdrowienia.
Blue Sky,

9
@ b.long Java dodała więcej niż stałą dla takich formatów zgodnych z ISO 8601. Java otrzymała zupełnie nową platformę do pracy z datą, która zawiera wbudowaną domyślną obsługę takich formatów. Zobacz nowy java.timeframework w Javie 8, zainspirowany Joda-Time , zastępujący kłopotliwe klasy java.util.Date, .Calendar i SimpleDateFormat.
Basil Bourque,

2
Czy to nie oznacza, że ​​musisz z góry znać format daty? Co zrobić, jeśli trzeba zaakceptować string1i string2, ale nie wiem, które otrzymasz.
Timmmm,

16
„Z” musi być w cudzysłowie
Kervin

7
@kervin Jeśli Z jest w cudzysłowie, to czy formatyzator nie będzie szukał znaku Z, a nie wszystkich ciągów przesunięcia, które może reprezentować? Wygląda na to, że cytowanie Z działałoby tylko przez przypadek, gdyby łańcuchy dat były w UTC.
spaaarky21,

201

Okej, na to pytanie już odpowiedziano, ale i tak upuszczę swoją odpowiedź. To może komuś pomóc.

Szukałem rozwiązania dla Androida (API 7).

  • Joda nie wchodziła w rachubę - jest ogromna i cierpi na powolną inicjalizację. Wydawało się to również poważną przesadą w tym konkretnym celu.
  • Odpowiedzi dotyczące javax.xmlnie będą działać w systemie Android API 7.

Skończyło się na implementacji tej prostej klasy. Obejmuje tylko najpopularniejszą formę ciągów ISO 8601, ale w niektórych przypadkach powinno to wystarczyć (gdy masz pewność, że dane wejściowe będą w tym formacie).

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

Uwaga dotycząca wydajności: za każdym razem tworzę nowy SimpleDateFormat, aby uniknąć błędu w systemie Android 2.1. Jeśli jesteś tak samo zaskoczony jak ja, zobacz tę zagadkę . W przypadku innych silników Java możesz buforować instancję w prywatnym polu statycznym (używając ThreadLocal, aby zapewnić bezpieczeństwo wątków).


2
Być może należałoby to uczynić osobnym pytaniem z własną odpowiedzią?
Thorbear

5
To była pierwsza strona, na której opublikowałem, kiedy szukałem odpowiedzi, więc wydawało się to odpowiednie. Dla większości programistów Java, Android nie jest dokładnie Java. Jednak w większości przypadków jedno działa tak samo jak drugie, więc wielu programistów Androida szuka hasła „java”, szukając tego.
wrygiel,

1
Pamiętaj, że nie uwzględnia to rozdzielczości milisekundowej. Łatwo to dodać.
Sky Kelsey,

6
Musiałem dodać .SSS na ułamek sekund, ale działa świetnie dzięki. Dlaczego to robisz s = s.substring(0, 22) + s.substring(23);- nie widzę sensu w tym
Dori,

1
input = input.replaceAll („[Zz]”, „+0000”); też będzie działać, a operacji podciągania można uniknąć.
Javanator,

115

java.time

API java.time (wbudowany w Java 8 i nowsze), sprawia, że to trochę łatwiejsze.

Jeśli wiesz, że dane wejściowe są w UTC , takie jak Z(dla Zulu) na końcu, Instantklasa może analizować.

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

Jeśli dane wejściowe mogą być inną wartością przesunięcia względem UTC , a nie UTC wskazywaną przez Z(Zulu) na końcu, użyj OffsetDateTimeklasy do parsowania.

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

Następnie wyodrębnij Instanti przekonwertuj na a java.util.Date, dzwoniąc from.

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

8
Ta odpowiedź jest zbyt ciężka. Z definicji java.util.Date nie ma strefy czasowej. Więc nie trzeba za wszystko, strefy czasowej związanej z kodem: the LocalDateTimei ZoneIdi atZone. Ten prosty liniowiec zrobi:java.util.Date date = Date.from( ZonedDateTime.parse( "2014-12-12T10:39:40Z" ).toInstant() );
Basil Bourque

5
@BasilBourque Jest to niepotrzebnie skomplikowane: Date.from(Instant.parse("2014-12-12T10:39:40Z" ));wystarczy.
assylias,

3
@assylias masz rację, ale zadziała to tylko wtedy, gdy ciąg daty jest strefą UTC, ISO8601 zezwala na dowolną strefę czasową ...
Adam

2
@Adam My bad - nie zdawałem sobie sprawy, że pytanie było bardziej ogólne niż twój przykład. Jako komentarz boczny OffsetDateTimewystarczyłoby przeanalizować ISO8601 (który nie zawiera informacji o strefie czasowej, a jedynie przesunięcie).
assylias

1
@assylias Dziękujemy za komentarz na temat Instantparsowania. Chociaż nie jest wystarczające dla tego konkretnego pytania, należy podkreślić ważne rozróżnienie. Więc dodałem drugi przykład kodu. Ups, właśnie zauważyłem, że pierwotnie nie jest to moja odpowiedź; Mam nadzieję, że Adam to pochwala.
Basil Bourque,

67

Biblioteka Jackson-databind ma również klasę ISO8601DateFormat , która to robi (rzeczywista implementacja w ISO8601Utils .

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

To nie do analizowania tej daty: 2015-08-11T13:10:00. I dostać String index out of range: 19. Patrząc na kod, wydaje się, że wymaga on określenia milisekund oraz strefy czasowej. Te powinny być opcjonalne.
Timmmm,

2
Zacytować dokumentację, parse format: [yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh:mm]]. Innymi słowy, milisekundy są opcjonalne, ale strefa czasowa jest obowiązkowa.
david_p

2
Ach tak, wygląda na to, że masz rację. Mimo to jestem prawie pewien, że ISO8601 pozwala ci ominąć strefę czasową, więc nadal jest źle. JodaTime działa jednak:new DateTime("2015-08-11T13:10:00").toDate()
Timmmm,

3
Ta klasa jest teraz przestarzała, nowa to StdDateFormat. W przeciwnym razie to działa tak samo.
JohnEye

51

tl; dr

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

Korzystanie z java.time

Nowy czas java.time pakiet w Javie 8 i nowszych został zainspirowany Joda-Time.

OffsetDateTimeKlasa reprezentuje moment na osi czasu z przesunięciem-z-UTC ale nie strefy czasowej.

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

Wywołanie toStringgeneruje ciąg znaków w standardowym formacie ISO 8601:

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

Aby zobaczyć tę samą wartość przez soczewkę UTC, wyodrębnij Instantlub dostosuj przesunięcie od +01:00do 00:00.

Instant instant = odt.toInstant();  

…lub…

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

W razie potrzeby dostosuj strefę czasową. Strefa czasowa to historia offsetu z-UTC wartości dla regionu, z zestawem zasad obchodzenia anomalie, takie jak czas letni (DST). Dlatego w miarę możliwości stosuj strefę czasową zamiast zwykłego przesunięcia.

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

O java.time

Środowisko java.time jest wbudowane w Javę 8 i nowsze wersje . Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date, Calendar, i SimpleDateFormat.

Projekt Joda-Time , teraz w trybie konserwacji , zaleca migrację do klas java.time .

Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj stos przepełnienia dla wielu przykładów i wyjaśnień. Specyfikacja to JSR 310 .

Możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Użyj sterownika JDBC zgodnego z JDBC 4.2 lub nowszym. Nie potrzeba ciągów, nie ma potrzeby java.sql.*klas.

Gdzie można uzyskać klasy java.time?

Projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Można znaleźć kilka przydatnych klas tutaj takie jak Interval, YearWeek, YearQuarter, i więcej .



27

Dla wersji Java 7

Możesz śledzić dokumentację Oracle: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

X - jest używany dla strefy czasowej ISO 8601

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

Oznacza to, że strefa czasowa jest wymagana . Zgodnie z ISO 8601 jest to opcjonalne. Jak są sekundy, itp Więc to tylko analizuje konkretny podzbiór ISO 8601.
Timmmm

1
Działa świetnie z Javą 1.8
Thiago Pereira

20

Rozwiązanie DatatypeConverter nie działa na wszystkich maszynach wirtualnych. Poniższe działa dla mnie:

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

Przekonałem się, że Joda nie działa od razu po wyjęciu z pudełka (specjalnie dla przykładu, który podałem powyżej ze strefą czasową w dniu, który powinien być ważny)


15

Myślę, że powinniśmy użyć

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

na datę 2010-01-01T12:00:00Z


5
Dlaczego jest to lepsza odpowiedź niż inne, w tym zaakceptowana odpowiedź z 76 głosami pozytywnymi?
Erick Robertson,

3
@ErickRobertson: Jest to prosty, gotowy do użycia, elastyczny, bez konwersji, a większość ludzi nie dba o strefy czasowe.
TWiStErRob

7
nie ma sensu pracować z czasami, jeśli nie zależy ci na strefach czasowych!
Dori,

16
Ten IGNORUJE strefy czasowej całkowicie. Używałem tego, dopóki nie zdałem sobie sprawy, że tak się dzieje, więc przełączyłem się na JodaTime.
Joshua Pinter,

3
Wyrzucenie strefy czasowej spowoduje po prostu błędy w pewnym momencie.
Bart van Kuik

11

Począwszy od Java 8, istnieje zupełnie nowy oficjalnie obsługiwany sposób, aby to zrobić:

    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
Jeśli ciąg ma format natychmiastowy, z końcowym Zprzesunięciem jako przesunięcie, nie musimy tego jawnie określać. Właśnie Instant i = Instant.parse(s);. Łańcuch w pytaniu miał +01:00, w którym to przypadku DateTimeFormatter.ISO_INSTANTnie działa (przynajmniej nie na mojej Javie 11).
Ole VV

2
@ OleV.V. Możesz użyć ISO_OFFSET_DATE_TIMEdo formatowania dat z przesunięciami, takimi jak +01:00( docs.oracle.com/javase/8/docs/api/java/time/format/… )
Lucas Basquerotto

1
To prawda, @LucasBasquerotto. Chociaż nie wspominając wyraźnie o tym formatyzatorze, odpowiedzi Adama i Bazylego Bourque już robią coś podobnego.
Ole VV

10

Innym bardzo prostym sposobem na analizowanie znaczników czasu ISO8601 jest użycie 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

Zauważ, że w Javie 8 możesz użyć klasy java.time.ZonedDateTime i jej parse(CharSequence text)metody statycznej .


Ciągi wejściowe w pytaniu mają tylko przesunięcie względem UTC, a nie pełną strefę czasową. Więc Instanti ZonedDateTimesą odpowiednie tutaj, nie ZonedDateTime.
Basil Bourque,

6

Obejściem dla Java 7+ jest użycie SimpleDateFormat:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);

Ten kod może analizować format ISO8601, taki jak:

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

Ale w Javie 6 SimpleDateFormatnie rozumie Xznaku i rzuca
IllegalArgumentException: Unknown pattern character 'X'
Musimy znormalizować datę ISO8601 do formatu możliwego do odczytania w Javie 6 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);
    }
}

Powyższa metoda zamienia [ Zz +0000] lub [ +01:00z +0100], gdy wystąpi błąd w Javie 6 (możesz wykryć wersję Java i zastąpić instrukcję try / catch instrukcją if).


Nie, kłopotliwe stare klasy daty i godziny, takie jak Datei SimpleDateFormatsą źle zaprojektowane, zagmatwane i wadliwe. Są teraz spuścizną, zastąpioną przez klasy java.time wbudowane w Javę 8 i nowsze wersje. W przypadku Java 6 i Java 7 duża część funkcji java.time została przeniesiona z powrotem do projektu ThreeTen-Backport . Znacznie lepiej jest dodać tę bibliotekę do aplikacji niż korzystać z klas starszych. Jednowierszowe rozwiązanie w java.time:OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" )
Basil Bourque

5

Napotkałem ten sam problem i rozwiązałem go za pomocą następującego kodu.

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

Wcześniej korzystałem SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());

Ale później odkryłem, że główną przyczyną wyjątku było yyyy-MM-dd'T'HH:mm:ss.SSSZ:

Więc użyłem

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

Dla mnie działało dobrze.


Właśnie tego potrzebowałem bez konieczności używania Joda-Time, XML API lub czegokolwiek innego. Właściwy wzór.
Philippe Gioseffi,


4

Java ma kilkanaście różnych sposobów analizowania daty i godziny, co pokazują doskonałe odpowiedzi tutaj. Ale, co jest zadziwiające, żadna z klas czasu Java nie w pełni implementuje ISO 8601!

W Javie 8 polecam:

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

Będzie to obsługiwać przykłady zarówno w UTC, jak i z przesunięciem, takie jak „2017-09-13T10: 36: 40Z” lub „2017-09-13T10: 36: 40 + 01: 00”. Sprawdzi się w większości przypadków użycia.

Ale nie obsługuje przykładów takich jak „2017-09-13T10: 36: 40 + 01”, która jest prawidłową datą i godziną ISO 8601.
Nie obsługuje też tylko daty, np. „2017-09-13”.

Jeśli musisz sobie z tym poradzić, sugeruję użycie najpierw wyrażenia regularnego do wąchania składni.

Jest tu ładna lista przykładów ISO 8601 z dużą ilością przypadków narożnych: https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/ Jestem nie zdaje sobie sprawy z żadnej klasy Java, która poradziłaby sobie z nimi wszystkimi.


OffsetDateTimezrobi i koncepcyjnie dopasuje datę i czas z przesunięciem lepiej.
Ole VV

Hej @ OleV.V. dzieki za sugestie. Niestety nie: OffsetDateTime.parse () zgłosi wyjątek dla kilku prawidłowych ciągów ISO 8601, np. „2017-09-13T10: 36: 40 + 01” lub „2017-09-13”
Daniel Winterstein

Chciałem tylko powiedzieć, że OffsetDateTimeobsługuje przykłady, którymi się posługujesz ZonedDateTime. Uważam, że nie obsługuje żadnego z przykładów, które ZonedDateTimetego nie robią. W tym sensie nie jest to żadna poprawa (ale i nic gorszego). Przepraszam, nie byłem całkowicie jasny.
Ole VV

1
Powinna to być odpowiedź zaakceptowana w 2020 r., Biorąc pod uwagę stan rzeczy.
slashCoder


3

Jak wspomnieli inni, Android nie ma dobrego sposobu na parsowanie / formatowanie dat ISO 8601 przy użyciu klas zawartych w zestawie SDK. Napisałem ten kod wiele razy, więc w końcu utworzyłem Gist, który zawiera klasę DateUtils, która obsługuje formatowanie i parsowanie dat ISO 8601 i RFC 1123. Gist zawiera również przypadek testowy pokazujący, co obsługuje.

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


2

SimpleDateFormat dla JAVA 1.7 ma fajny wzór dla formatu ISO 8601.

Klasa SimpleDateFormat

Oto co zrobiłem:

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

2
Zw formacie ciąg nie jest strefą czasową ISO 8601, powinieneś użyć X(lub XXlub XXX), jeśli chcesz strefy czasowej ISO 8601
Vojta

d jest typu String
Tim Child

1

Zrób to tak:

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

}

Oto wynik:

Śr. 19 paź 15:15:36 CST 2016


1

Użyj ciągu jak LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)


1

Dziwi mnie, że nawet jedna biblioteka Java nie obsługuje wszystkich formatów daty ISO 8601 zgodnie z https://en.wikipedia.org/wiki/ISO_8601 . Joda DateTime obsługiwał większość z nich, ale nie wszystkie, dlatego dodałem niestandardową logikę do obsługi wszystkich z nich. Oto moja implementacja.

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

Mały test, który pokazuje, jak parsować datę w ISO8601 i że LocalDateTime nie obsługuje DST.

 @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
Do Twojej wiadomości, strasznie kłopotliwe klasy daty i czasu, takie jak java.util.Date, java.util.Calendari java.text.SimpleDateFormatsą teraz spuścizną , wyparte przez klasy java.time wbudowane w Javę 8 i nowsze wersje . Zobacz samouczek Oracle .
Basil Bourque

Masz rację, że LocalDateTimenie obsługuje czasu letniego (DST), ponieważ w ogóle nie obsługuje strefy czasowej. Do tego potrzebujemy ZonedDateTime. Proponowanie Datei SimpleDateFormatjest - IMHO złe.
Ole VV

1
Rzeczywiście działa ZonedDateTime. I java.time.Instant jest również dobrą alternatywą do obsługi DST. Wiem, że java.util.Date jest przestarzała i nie powinna być używana, ale właśnie odpowiadałem na oryginalne pytanie: Jak przekonwertować ciąg
znaków

0

Miałem podobną potrzebę: musiałem móc przeanalizować dowolną datę zgodną z ISO8601, nie znając z góry dokładnego formatu, i chciałem lekkiego rozwiązania, które również działałoby na Androidzie.

Kiedy przejrzałem swoje potrzeby, natknąłem się na to pytanie i zauważyłem, że AFAIU, żadna odpowiedź nie odpowiada moim potrzebom. Więc opracowałem jISO8601 i wrzuciłem go do maven central.

Po prostu dodaj w tobie pom.xml:

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

a potem możesz iść:

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

Mam nadzieję, że to pomoże.



-1

Funkcja podstawowa Dzięki uprzejmości: @wrygiel.

Ta funkcja może konwertować format ISO8601 na datę Java, która obsługuje wartości przesunięcia. Zgodnie z definicją ISO 8601 przesunięcie można podać w różnych formatach.

±[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

Ta klasa ma statyczne metody konwersji

  • Ciąg ISO8601 do obiektu Data (lokalna strefa czasowa)
  • Data do ciągu ISO8601
  • Czas letni jest automatycznie obliczany

Przykładowe ciągi ISO8601

/*       "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
Uwaga - DateFormat i klasy pochodne nie są kompatybilne z wielowątkowością! Korzystanie ze statycznych obiektów SimpleDateFormat, takich jak DATE_FORMAT_1 i DATE_FORMAT_2, oznacza, że ​​wiele wątków wywołujących funkcje ISO8601DateFormatter będzie współużytkować ten sam obiekt DateFormat. Prowadzi to do uszkodzenia danych i zwracania niepoprawnych dat z wywołań DateFormat. Aby to naprawić, powinieneś po prostu wprowadzić ciągi znaków wzorca i utworzyć lokalne zmienne SimpleDateFormat, gdy zajdzie taka potrzeba. Zapewni to, że każdy obiekt jest używany tylko przez jeden wątek.
Theo

Lepszym rozwiązaniem dla bezpieczeństwa wątków jest użycie biblioteki daty i godziny zbudowanej dla bezpieczeństwa wątków. W Javie tym światem może być Joda-Time lub java.time.
Basil Bourque,

-1

Wydawało mi się, że to działa najlepiej:

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


}

Musiałem przekonwertować ciągi daty / JavaScript dla Java na Java. Znalazłem powyższe prace z zaleceniem. Było kilka przykładów użycia SimpleDateFormat, które były blisko, ale nie wydawały się być podzbiorem, zgodnie z zaleceniami:

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

i obsługiwany przez PLIST i JavaScript Strings i takie właśnie było to, czego potrzebowałem.

To wydaje się być najczęstszą formą łańcucha ISO8601 i dobrym podzbiorem.

Podają przykłady:

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.

Mam też szybką wersję:

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

Nie przeprowadziłem testu porównawczego, ale myślę, że będzie to dość szybkie. Wydaje się, że działa. :)

@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

Myślę, że to, co wielu ludzi chce robić, to analizuje ciągi dat JSON. Istnieje duża szansa, że ​​jeśli przejdziesz na tę stronę, możesz chcieć przekonwertować datę JSON JavaScript na datę Java.

Aby pokazać, jak wygląda ciąg daty JSON:

    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)

Ciąg daty JSON to 2013-12-14T01: 55: 33.412Z.

Daty nie są objęte specyfikacją JSON, powiedzmy, ale powyższy jest bardzo specyficznym formatem ISO 8601, podczas gdy ISO_8601 jest znacznie większy i jest to tylko podzbiór, choć bardzo ważny.

Zobacz http://www.json.org Zobacz http://en.wikipedia.org/wiki/ISO_8601 Zobacz http://www.w3.org/TR/NOTE-datetime

Tak się składa, że ​​napisałem parser JSON i parser PLIST, z których oba używają ISO-8601, ale nie tych samych bitów.

/*
    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);
}

Napisałem dwa sposoby, aby to zrobić dla mojego projektu. Jeden standard, jeden szybki.

Ponownie ciąg daty JSON jest bardzo specyficzną implementacją ISO 8601 ....

(Drugą zamieściłem w drugiej odpowiedzi, która powinna działać dla dat PLIST, które są w innym formacie ISO 8601).

Data JSON jest następująca:

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


}

Pliki PLIST (ASCII nie GNUNext) również używają ISO 8601, ale nie milisekund, więc ... nie wszystkie daty ISO-8601 są takie same. (Przynajmniej nie znalazłem jeszcze takiego, który używa milis, a analizator składni, który widziałem, całkowicie pomija strefę czasową OMG).

Teraz szybka wersja (można ją znaleźć w Boon).

public static Date fromJsonDate( String string ) {

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

}

Zauważ, że Reflection.toCharArray używa niebezpiecznych, jeśli jest dostępne, ale domyślnie string.toCharArray, jeśli nie.

(Możesz go usunąć z przykładu, zastępując Reflection.toCharArray (string) string.toCharArray ()).

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

}

IsJsonDate jest implementowany w następujący sposób:

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

W każdym razie ... przypuszczam, że sporo osób, które tu przychodzą ... może szukało ciągu daty JSON i chociaż jest to data ISO-8601, jest to bardzo konkretna, wymagająca bardzo dokładnej analizy.

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

Zobacz https://github.com/RichardHightower/boon Boon ma parser PLIST (ASCII) i parser JSON.

Analizator składni JSON jest najszybszym analizatorem składni JSON w języku Java, jaki znam.

Niezależnie zweryfikowane przez kolesie z Gatling Performance.

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

Ma najszybszy parser JSON dla strumieni, czytników, bajtów [], char [], CharSequence (StringBuilder, CharacterBuffer) i String.

Zobacz więcej testów porównawczych na:

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


Ta odpowiedź na temat JSON jest nie na temat pytania. Co więcej, to pytanie jest nieprawidłowe, ponieważ nie ma czegoś takiego jak „data JSON” wśród bardzo niewielu typów danych JSON . W dzisiejszych czasach cały ten kod można zastąpić wywołaniem jednowierszowym wbudowanej funkcji Java:Instant.parse( "2013-12-14T01:55:33.412Z" )
Basil Bourque,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.