Próbuję przekonwertować ciąg w formacie ISO 8601 na plik java.util.Date
.
Stwierdziłem, że wzorzec yyyy-MM-dd'T'HH:mm:ssZ
jest zgodny z ISO8601, jeśli jest używany z ustawieniami regionalnymi (porównaj próbkę).
Jednak używając java.text.SimpleDateFormat
nie 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.
Odpowiedzi:
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:
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 ciCalendar
obiekt i możesz po prostu użyć na nim getTime (), jeśli potrzebujeszDate
obiektu.Prawdopodobnie mógłbyś również użyć Joda-Time , ale nie wiem, dlaczego miałbyś się tym przejmować.
źródło
Sposób, który jest błogosławiony przez dokumentację Java 7 :
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
źródło
java.time
framework w Javie 8, zainspirowany Joda-Time , zastępujący kłopotliwe klasy java.util.Date, .Calendar i SimpleDateFormat.string1
istring2
, ale nie wiem, które otrzymasz.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).
javax.xml
nie 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).
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).
źródło
s = s.substring(0, 22) + s.substring(23);
- nie widzę sensu w tymjava.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,Instant
klasa może analizować.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żyjOffsetDateTime
klasy do parsowania.Następnie wyodrębnij
Instant
i przekonwertuj na ajava.util.Date
, dzwoniącfrom
.źródło
LocalDateTime
iZoneId
iatZone
. Ten prosty liniowiec zrobi:java.util.Date date = Date.from( ZonedDateTime.parse( "2014-12-12T10:39:40Z" ).toInstant() );
Date.from(Instant.parse("2014-12-12T10:39:40Z" ));
wystarczy.OffsetDateTime
wystarczyłoby przeanalizować ISO8601 (który nie zawiera informacji o strefie czasowej, a jedynie przesunięcie).Instant
parsowania. 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.Biblioteka Jackson-databind ma również klasę ISO8601DateFormat , która to robi (rzeczywista implementacja w ISO8601Utils .
źródło
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.[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.new DateTime("2015-08-11T13:10:00").toDate()
tl; dr
Korzystanie z java.time
Nowy czas java.time pakiet w Javie 8 i nowszych został zainspirowany Joda-Time.
OffsetDateTime
Klasa reprezentuje moment na osi czasu z przesunięciem-z-UTC ale nie strefy czasowej.Wywołanie
toString
generuje ciąg znaków w standardowym formacie ISO 8601:Aby zobaczyć tę samą wartość przez soczewkę UTC, wyodrębnij
Instant
lub dostosuj przesunięcie od+01:00
do00:00
.…lub…
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.
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
, iSimpleDateFormat
.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 .źródło
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
źródło
Rozwiązanie DatatypeConverter nie działa na wszystkich maszynach wirtualnych. Poniższe działa dla mnie:
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)
źródło
Myślę, że powinniśmy użyć
na datę
2010-01-01T12:00:00Z
źródło
Począwszy od Java 8, istnieje zupełnie nowy oficjalnie obsługiwany sposób, aby to zrobić:
źródło
Z
przesunięciem jako przesunięcie, nie musimy tego jawnie określać. WłaśnieInstant i = Instant.parse(s);
. Łańcuch w pytaniu miał+01:00
, w którym to przypadkuDateTimeFormatter.ISO_INSTANT
nie działa (przynajmniej nie na mojej Javie 11).ISO_OFFSET_DATE_TIME
do formatowania dat z przesunięciami, takimi jak+01:00
( docs.oracle.com/javase/8/docs/api/java/time/format/… )Innym bardzo prostym sposobem na analizowanie znaczników czasu ISO8601 jest użycie
org.apache.commons.lang.time.DateUtils
:źródło
java.time
Zauważ, że w Javie 8 możesz użyć klasy java.time.ZonedDateTime i jej
parse(CharSequence text)
metody statycznej .źródło
Instant
iZonedDateTime
są odpowiednie tutaj, nieZonedDateTime
.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
SimpleDateFormat
nie rozumieX
znaku i rzucaIllegalArgumentException: Unknown pattern character 'X'
Musimy znormalizować datę ISO8601 do formatu możliwego do odczytania w Javie 6
SimpleDateFormat
.Powyższa metoda zamienia [
Z
z+0000
] lub [+01:00
z+0100
], gdy wystąpi błąd w Javie 6 (możesz wykryć wersję Java i zastąpić instrukcję try / catch instrukcją if).źródło
Date
iSimpleDateFormat
są ź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" )
Napotkałem ten sam problem i rozwiązałem go za pomocą następującego kodu.
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.
źródło
Możesz także użyć następującej klasy -
Link do dokumentu Java Doc - Hierarchy For Package org.springframework.extensions.surf.maven.plugin.util
źródło
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:
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.
źródło
OffsetDateTime
zrobi i koncepcyjnie dopasuje datę i czas z przesunięciem lepiej.OffsetDateTime
obsługuje przykłady, którymi się posługujeszZonedDateTime
. Uważam, że nie obsługuje żadnego z przykładów, któreZonedDateTime
tego nie robią. W tym sensie nie jest to żadna poprawa (ale i nic gorszego). Przepraszam, nie byłem całkowicie jasny.Apache Jackrabbit używa formatu ISO 8601 do utrwalania dat, a istnieje klasa pomocnicza do ich analizy:
org.apache.jackrabbit.util.ISO8601
W zestawie jackrabbit-jcr-commons .
źródło
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
źródło
SimpleDateFormat dla JAVA 1.7 ma fajny wzór dla formatu ISO 8601.
Klasa SimpleDateFormat
Oto co zrobiłem:
źródło
Z
w formacie ciąg nie jest strefą czasową ISO 8601, powinieneś użyćX
(lubXX
lubXXX
), jeśli chcesz strefy czasowej ISO 8601Zrób to tak:
Oto wynik:
Śr. 19 paź 15:15:36 CST 2016
źródło
Użyj ciągu jak
LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)
źródło
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.
źródło
Mały test, który pokazuje, jak parsować datę w ISO8601 i że LocalDateTime nie obsługuje DST.
źródło
java.util.Date
,java.util.Calendar
ijava.text.SimpleDateFormat
są teraz spuścizną , wyparte przez klasy java.time wbudowane w Javę 8 i nowsze wersje . Zobacz samouczek Oracle .LocalDateTime
nie obsługuje czasu letniego (DST), ponieważ w ogóle nie obsługuje strefy czasowej. Do tego potrzebujemyZonedDateTime
. ProponowanieDate
iSimpleDateFormat
jest - IMHO złe.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
:a potem możesz iść:
Mam nadzieję, że to pomoże.
źródło
Aby po prostu sformatować taką datę, następujące działało dla mnie w aplikacji opartej na Javie 6. W projekcie Thymeleaf jest
DateFormat
klasa,JacksonThymeleafISO8601DateFormat
która wstawia brakujący dwukropek:https://github.com/thymeleaf/thymeleaf/blob/40d27f44df7b52eda47d1bc6f1b3012add6098b3/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java
Użyłem go do kompatybilności formatu daty ECMAScript.
źródło
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.
Ta klasa ma statyczne metody konwersji
Przykładowe ciągi ISO8601
}
źródło
Wydawało mi się, że to działa najlepiej:
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:
Mam też szybką wersję:
...
Nie przeprowadziłem testu porównawczego, ale myślę, że będzie to dość szybkie. Wydaje się, że działa. :)
źródło
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:
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.
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:
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).
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 ()).
IsJsonDate jest implementowany w następujący sposób:
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.
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
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
źródło
Instant.parse( "2013-12-14T01:55:33.412Z" )