807 Stimmen

Konvertierung von ISO 8601-konformem String in java.util.Date

Ich versuche, eine ISO 8601 formatierte Zeichenkette in eine java.util.Date .

Ich habe das Muster gefunden yyyy-MM-dd'T'HH:mm:ssZ ISO8601-konform zu sein, wenn sie mit einem Gebietsschema verwendet wird (siehe Beispiel).

Allerdings ist die Verwendung der java.text.SimpleDateFormat kann ich den korrekt formatierten String nicht umwandeln 2010-01-01T12:00:00+01:00 . Ich muss es zunächst in 2010-01-01T12:00:00+0100 , ohne den Doppelpunkt.

Die derzeitige Lösung lautet also

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

was natürlich nicht so schön ist. Übersehe ich etwas oder gibt es eine bessere Lösung?


Antwort

Dank des Kommentars von JuanZe habe ich die Joda-Time Magie, sie ist auch hier beschrieben .

Die Lösung lautet also

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

Oder einfacher: Verwenden Sie den Standard-Parser über den Konstruktor:

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

Für mich ist das schön.

283 Stimmen

Seien Sie darauf gefasst, dass Sie eine Menge "Use JodaTime"-Antworten erhalten werden...

3 Stimmen

@Ice09: Wenn die API-Dokumentation für DateTimeFormat korrekt ist (die JoDa-Dokumentation kann allerdings irreführend, falsch oder unvollständig sein), ist das Muster, das Sie in Ihrer eigenen "Antwort" verwendet haben, nicht mit ISO8601 kompatibel.

0 Stimmen

@jarnbjo: Danke für den Kommentar - du könntest Recht haben, ich habe noch einmal nachgeschaut und bin auf die viel bessere Lösung ISODateTimeFormat.dateTimeNoMillis() gekommen, die irgendwie garantiert, dass das richtige Format verwendet wird.

76voto

Basil Bourque Punkte 256611

Tl;dr

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

Verwendung von java.time

Die neue java.time Paket in Java 8 und später wurde von Joda-Time inspiriert.

El OffsetDateTime Klasse repräsentiert einen Moment auf der Zeitachse mit einer Abweichung von der UTC aber nicht eine Zeitzone.

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

Aufruf von toString erzeugt eine Zeichenkette im Standardformat ISO 8601:

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

Um denselben Wert durch die Linse von UTC zu sehen, extrahieren Sie eine Instant oder stellen Sie den Offset von +01:00 a 00:00 .

Instant instant = odt.toInstant();  

oder

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

Stellen Sie gegebenenfalls eine Zeitzone ein. A Zeitzone ist eine Geschichte von Abweichung von der UTC Werte für eine Region, mit einer Reihe von Regeln für die Behandlung von Anomalien wie Sommerzeit (DST). Wenden Sie also, wann immer möglich, eine Zeitzone anstelle eines bloßen Offsets an.

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

Für einen reinen Datumswert, verwenden Sie LocalDate .

LocalDate ld = LocalDate.of( 2010 , Month.JANUARY , 1 ) ;

Oder:

LocalDate ld = LocalDate.parse( "2010-01-01" ) ;

Über java.time

El java.time Framework ist in Java 8 und höher integriert. Diese Klassen verdrängen die lästigen alten Erbe Datum-Zeit-Klassen wie java.util.Date , Calendar , & SimpleDateFormat .

Weitere Informationen finden Sie in der Oracle-Tutorial . Und suchen Sie auf Stack Overflow nach vielen Beispielen und Erklärungen. Spezifikation ist JSR 310 .

El Joda-Time Projekt, jetzt in Wartungsmodus rät zur Migration auf den java.time Klassen.

Sie können umtauschen java.time Objekte direkt mit Ihrer Datenbank. Verwenden Sie eine JDBC-Treiber übereinstimmend mit JDBC 4.2 oder später. Keine Notwendigkeit für Strings, keine Notwendigkeit für java.sql.* Klassen. Unterstützung von Hibernate 5 und JPA 2.2 java.time .

Wo erhält man die java.time-Klassen?


2 Stimmen

Ich glaube nicht, dass dies hilfreich ist, da es keine ISO 8601 Datumsangaben analysiert, sondern nur eine sehr spezifische Untergruppe. Zum Beispiel, java.time.OffsetDateTime.parse ( "2010-01-01" ) scheitert

0 Stimmen

@phil294 Alle der java.time Klassen parsen Eingaben im ISO 8601-Standardformat entsprechend der jeweiligen Klasse. Ihr Beispiel für "2010-01-01" ist nur ein Datum und wird daher von der Nur-Datum-Klasse geparst, LocalDate . Ex: LocalDate.parse( "2010-01-01" ) . Ihre Beispielklasse von OffsetDateTime ist für ein Datum mit einer Uhrzeit und einem Offset (eine Anzahl von Stunden-Minuten-Sekunden vor/nach UTC). Also OffsetDateTime analysiert ISO 8601-formatierte Eingaben mit einem Datum, einer Uhrzeit und einem Offset. Ex: OffsetDateTime.parse( "2010-01-01T12:30:00-08:00" ) . Code live auf IdeOne.com ausführen .

74voto

david_p Punkte 4654

El Jackson-databind-Bibliothek hat auch ISO8601DateFormat-Klasse die das tut (aktuelle Implementierung in ISO8601Utils .

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

0 Stimmen

Dieses Datum kann nicht analysiert werden: 2015-08-11T13:10:00 . Ich bekomme String index out of range: 19 . Wenn ich mir den Code ansehe, scheint es, dass die Angabe der Millisekunden und der Zeitzone erforderlich ist. Diese sollten optional sein.

3 Stimmen

Um die Dokumentation zu zitieren, lautet das Parse-Format: [yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z‌​|[+-]hh:mm]] . Mit anderen Worten: Die Angabe der Millisekunden ist fakultativ, die Angabe der Zeitzone ist obligatorisch.

2 Stimmen

Ja, es sieht tatsächlich so aus, als hätten Sie recht. Trotzdem bin ich mir ziemlich sicher, dass ISO8601 es erlaubt, die Zeitzone wegzulassen, also ist es immer noch falsch. JodaTime funktioniert aber: new DateTime("2015-08-11T13:10:00").toDate()

35voto

d.danailov Punkte 9178

Für Java Version 7

Sie können der Oracle-Dokumentation folgen: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

X - wird für die ISO 8601-Zeitzone verwendet

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

0 Stimmen

Das bedeutet, die Zeitzone ist erforderlich . Nach ISO 8601 ist sie fakultativ. Gleiches gilt für die Sekunden usw. Es wird also nur eine bestimmte Teilmenge von ISO 8601 geparst.

3 Stimmen

Funktioniert hervorragend mit Java 1.8

23voto

James Scriven Punkte 7198

Die DatatypeConverter-Lösung funktioniert nicht in allen VMs. Die folgende Lösung funktioniert bei mir:

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

Ich habe festgestellt, dass Joda nicht out of the box funktioniert (speziell für das Beispiel, das ich oben mit der Zeitzone an einem Datum, das gültig sein sollte)

17voto

Toby Punkte 359

Ich denke, wir sollten die

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

für Datum 2010-01-01T12:00:00Z

5 Stimmen

Warum ist dies eine bessere Antwort als die anderen, einschließlich der akzeptierten Antwort mit 76 Bewertungen?

3 Stimmen

@ErickRobertson: Es ist einfach, sofort einsatzbereit, flexibel, keine Umrechnungen, und den meisten Leuten sind die Zeitzonen egal.

7 Stimmen

Es macht nicht viel Sinn, mit Zeiten zu arbeiten, wenn man sich nicht um Zeitzonen kümmert!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X