2010-04-05 13 views
61

Próbuję analizować datę, która wygląda tak:SimpleDateFormat Data parsowania z „Z” dosłowny

2010-04-05T17:16:00Z 

Jest to ważna data za http://www.ietf.org/rfc/rfc3339.txt. Literał "Z" oznacza, że ​​UTC jest preferowanym punktem odniesienia dla określonego czasu. "

Gdy próbuję analizować go przy użyciu SimpleDateFormat i ten wzór:

yyyy-MM-dd'T'HH:mm:ss 

To będzie analizowany jako Pon 05 kwietnia 2010 17:16:00 CEST

SimpleDateFormat jest w stanie analizować ciąg z tych wzorów:

yyyy-MM-dd'T'HH:mm:ssz 
yyyy-MM-dd'T'HH:mm:ssZ 

mogę jawnie ustawić strefę czasową, aby korzystać w SimpleDateFormat uzyskać spodziewanych rezultatów, ale nie sądzę, że powinno być konieczne. Czy jest coś, czego mi brakuje? Czy istnieje alternatywny parser daty?

+11

Sufiks "Z" w sygnaturze czasowej nie powinien mylić z Z lub z we wzorze. W języku Java 7 można przeanalizować sufiks ISO8601 za pomocą SimpleDateFormat, używając litery wzoru "X". –

+0

FYI, kłopotliwe stare klasy czasu i daty, takie jak 'SimpleTextFormat' są teraz [starszeństwem] (https://en.wikipedia.org/wiki/Legacy_system), wypierane przez [java.time] (https: // docs .oracle.com/javase/8/docs/api/java/time/package-summary.html). Zobacz [Tutorial by Oracle] (https://docs.oracle.com/javase/tutorial/datetime/TOC.html). –

Odpowiedz

28

We wzorze uwzględnienie składowej daty i godziny "z" wskazuje, że format strefy czasowej musi być zgodny ze standardem "General time zone", którego przykłady to Pacific Standard Time; PST; GMT-08:00.

"Z" wskazuje, że strefa czasowa jest zgodna ze standardem RFC 822 time zone, np. -0800.

Chyba trzeba DatatypeConverter ...

@Test 
public void testTimezoneIsGreenwichMeanTime() throws ParseException { 
    final Calendar calendar = javax.xml.bind.DatatypeConverter.parseDateTime("2010-04-05T17:16:00Z"); 
    TestCase.assertEquals("gotten timezone", "GMT+00:00", calendar.getTimeZone().getID()); 
} 
+0

tak, rozumiem to. Permutacje z/Z były po prostu mnie widząc, czy coś będzie trzymać. Nadal pozostaje, że moja data jest ważna i powinien istnieć prawidłowy wzór do jej przeanalizowania. – DanInDC

+0

Starałem się zapamiętać klasę "DatatypeConverter", którą kolega pokazał mi dopiero niedawno. –

+0

Zobacz także poprzednią odpowiedź http://stackoverflow.com/questions/2201925/converting-iso8601-compliant-string-to-java-util-date –

3

Strefa czasowa powinna być taka, jak "GMT + 00: 00" lub 0000, aby być poprawnie przeanalizowana przez SimpleDateFormat - możesz zastąpić Z tą konstrukcją.

2

Projekt restlet zawiera klasę InternetDateFormat że można analizować RFC 3339 daty.

Restlet InternetDateFormat

Choć może po prostu chcesz wymienić tyłu „z” z „UTC”, zanim przetworzy go.

+0

Restlet InternetDateFormat działał dobrze dla mnie – emmby

46

Java nie analizuje poprawnie dat ISO.

Podobny do odpowiedzi McKenziego.

Po prostu zmień Z przed analizą.

Kod

String string = "2013-03-05T18:05:05.000Z"; 
String defaultTimezone = TimeZone.getDefault().getID(); 
Date date = (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).parse(string.replaceAll("Z$", "+0000")); 

System.out.println("string: " + string); 
System.out.println("defaultTimezone: " + defaultTimezone); 
System.out.println("date: " + (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).format(date)); 

Wynik

string: 2013-03-05T18:05:05.000Z 
defaultTimezone: America/New_York 
date: 2013-03-05T13:05:05.000-0500 
+0

Co za wstyd! Dzięki za podpowiedź –

+17

Java 7 dodała literę X do analizy danych ISO. –

+0

@Dave, dzięki za aktualizację! – Alex

25

Data jesteś parsowania jest w formacie ISO8601.

w Javie 7 Wzór do odczytania i zastosować przyrostek stref czasowych powinien przeczytać yyyy-MM-dd'T'HH:mm:ssX

+4

To powinna być poprawna odpowiedź zamiast zaakceptowanej odpowiedzi. –

+0

Ponadto, jeśli chcesz przeanalizować minuty w strefie czasowej, po prostu dodaj drugie lub trzecie "X": "rrrr-MM-dd'T'HH: mm: ssXX" lub "rrrr-MM-dd'T'HH : mm: ssXXX'. Więcej szczegółów można znaleźć w [SimpleDateFormat - strefa czasowa ISO 8601] (https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html#iso8601timezone). – mateuscb

17

tl; dr

Instant.parse ("2010-04-05T17:16:00Z") 

ISO 8601 Standardowy

ciąg jest zgodny ze standardem (którego ISO 8601 wspomniany RFC 3339 jest profilem).

Unikać j.u.Date

W java.util.Date i .Calendar klasy wiązane z Java są notorycznie kłopotliwe. Unikaj ich.

Zamiast tego należy użyć biblioteki Joda-Time lub nowego pakietu java.time w języku Java 8. Obie metody używają ISO 8601 jako domyślnego do analizowania i generowania reprezentacji ciągów wartości daty i godziny.

java.time

java.time ramy wbudowany w Java 8 i później wypiera kłopotliwe starych klas java.util.Date/.Calendar. Nowe klasy zostały zainspirowane cieszącym się dużym powodzeniem frameworkem Joda-Time, który ma być jego następcą, podobnym do koncepcji, ale zmienionym na nowo. Zdefiniowany przez JSR 310. Rozszerzony o projekt ThreeTen-Extra. Zobacz Tutorial.

Klasa Instant w java.time reprezentuje moment na osi czasu w strefie czasowej UTC.

Na końcu wprowadzanego ciągu znaków Zulu oznacza UTC. Taki ciąg może być bezpośrednio przetwarzany przez klasę Instant, bez konieczności określania formatyzatora.

String input = "2010-04-05T17:16:00Z"; 
Instant instant = Instant.parse (input); 

Zrzut na konsolę.

System.out.println ("instant: " + instant); 

natychmiastowy: 2010-04-05T17: 16: 00Z

Stamtąd można zastosować strefę czasową (ZoneId), aby dostosować ten Instant do ZonedDateTime. Przeszukaj przepełnienie stosu w celu omówienia i przykłady.

Jeśli musisz użyć obiektu java.util.Date, możesz przekonwertować, wywołując nowe metody konwersji dodane do starych klas, na przykład metodę statyczną java.util.Date.from(Instant).

java.util.Date date = java.util.Date.from(instant); 

Joda czasie

przykład w Joda-Time 2.5.

Konwertuj na UTC.

DateTime dateTimeUtc = dateTime.withZone(DateTimeZone.UTC); 

Konwertuj na java.util.Date, jeśli to konieczne.

java.util.Date date = dateTime.toDate(); 
+0

Proszę pamiętać o tym artykule Stephena Colebourne'a: ​​[Dlaczego JSR-310 nie jest Joda-Time] (http://blog.joda.org/2009/11/why-jsr-310-isn-joda-time_4941.html) – JJD

5

'x' działa tylko jeśli częściowe sekund nie są obecne: czyli wzór SimpleDateFormat z

"rrrr-mm-dd'T'GG: mm: SSX"

poprawnie zanalizować

"2008-01-31T00: 00: 00S"

ale

„rrrr MM-dd'T'GG: m m: ss.SX”

nie będzie analizować

"2008-01-31T00: 00: 00.000Z"

Smutne, ale prawdziwe, data-czas z częściowym sekund nie wydaje się być ważna data ISO: http://en.wikipedia.org/wiki/ISO_8601

+2

To jest strasznie denerwujące. –

+0

Cytat ze strony odwołanych stron wiki: "Dziesiętne ułamki mogą być dodawane do dowolnego z trzech elementów czasowych. [...] Nie ma ograniczenia liczby miejsc dziesiętnych dla ułamka dziesiętnego. Jednak liczba miejsc dziesiętnych musi zostać uzgodnione przez łączące się strony." " Z "jest niezależnym pojęciem dla stref czasowych Więc częściowe sekundy SĄ ważnymi datami ISO Byłoby miło sparsować. (Może to nie jest" Prosty format daty "?)) – MGM

2

mogę dostarczyć kolejną odpowiedź, że znaleziony przez api-client-library przez Google

try { 
    DateTime dateTime = DateTime.parseRfc3339(date); 
    dateTime = new DateTime(new Date(dateTime.getValue()), TimeZone.getDefault()); 
    long timestamp = dateTime.getValue(); // get date in timestamp 
    int timeZone = dateTime.getTimeZoneShift(); // get timezone offset 
} catch (NumberFormatException e) { 
    e.printStackTrace(); 
} 

Instrukcja użytkownika,
https://developers.google.com/api-client-library/java/google-api-java-client/setup#download

Oto odniesienia API,
https://developers.google.com/api-client-library/java/google-http-java-client/reference/1.20.0/com/google/api/client/util/DateTime

Kod źródłowy DateTime klasy,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/main/java/com/google/api/client/util/DateTime.java

DateTime testy jednostkowe,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/test/java/com/google/api/client/util/DateTimeTest.java#L121

2

W odniesieniu do JSR-310 innym projekcie zainteresowania może być threetenbp.

JSR-310 zapewnia nową datę i godzinę biblioteki dla Java SE 8. Projekt ten jest backport Java SE 6 i 7.

W przypadku, gdy pracują na projektu Android możesz wypróbować ThreeTenABP library.

compile "com.jakewharton.threetenabp:threetenabp:${version}" 

JSR-310 została ujęta w Java 8 jako java.time. * Pakiet. Jest to pełny zamiennik dla chory interfejs API Data i Kalendarz zarówno w Javie, jak i Androidzie. JSR-310 został przeniesiony do Java 6 przez swojego twórcę, Stephena Colebourne, z którego ta biblioteka została dostosowana.

7

Według ostatniego rzędu na Date and Time Patterns stole Java 7 API

X Strefa czasowa ISO 8601 strefa czasowa -08; -0800; -08: 00

Dla strefy czasowej ISO 8601 należy użyć X (-08 lub Z); XX (-0800 lub Z); i XXX (-08: 00 lub Z), aby przeanalizować "2010-04-05T17: 16: 00Z" jest albo "yyyy-MM-dd'T'HH: mm: ssX" lub "yyyy-MM- dd'T'HH: mm: ssXX "lub" rrrr-MM-dd'T'HH: mm: ssXXX " powinien działać.

System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX").parse("2010-04-05T17:16:00Z")); 
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXX").parse("2010-04-05T17:16:00Z")); 
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").parse("2010-04-05T17:16:00Z")); 

będzie poprawnie wydrukować 'Mon Apr 05 13:16:00 EDT 2010'

+0

To powinno być zaakceptowana odpowiedź, ponieważ pokazuje, jak analizować ciąg daty za pomocą SimpleDateFormat, jak pytanie zadane. – davidgyoung

0

Pod Java 8 użycia predefiniowanego DateTimeFormatter.ISO_DATE_TIME

DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME; 
ZonedDateTime result = ZonedDateTime.parse("2010-04-05T17:16:00Z", formatter); 

Chyba jej najprostszy sposób

0

Ponieważ java 8 wystarczy użyć ZonedDateTime.parse("2010-04-05T17:16:00Z")