Ich versuche, einen ISO 8601- formatierten String in einen zu konvertieren java.util.Date
.
Ich habe festgestellt, dass das Muster yyyy-MM-dd'T'HH:mm:ssZ
ISO8601-kompatibel ist, wenn es mit einem Gebietsschema verwendet wird (vergleiche Beispiel).
Mit dem java.text.SimpleDateFormat
kann ich den korrekt formatierten String jedoch nicht konvertieren 2010-01-01T12:00:00+01:00
. Ich muss es zuerst konvertieren 2010-01-01T12:00:00+0100
, ohne den Doppelpunkt.
Die aktuelle Lösung ist 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 offensichtlich nicht so schön ist. Vermisse ich etwas oder gibt es eine bessere Lösung?
Antworten
Dank JuanZes Kommentar habe ich die Joda-Zeit- Magie gefunden, die auch hier beschrieben wird .
Die Lösung ist also
DateTimeFormatter parser2 = ISODateTimeFormat.dateTimeNoMillis();
String jtdate = "2010-01-01T12:00:00+01:00";
System.out.println(parser2.parseDateTime(jtdate));
Oder verwenden Sie einfach den Standardparser über den Konstruktor:
DateTime dt = new DateTime( "2010-01-01T12:00:00+01:00" ) ;
Für mich ist das schön.
Antworten:
Leider sind die für SimpleDateFormat verfügbaren Zeitzonenformate (Java 6 und früher) nicht ISO 8601- konform. SimpleDateFormat versteht Zeitzonenzeichenfolgen wie "GMT + 01: 00" oder "+0100", letzteres gemäß RFC # 822 .
Auch wenn Java 7 die Unterstützung für Zeitzonendeskriptoren gemäß ISO 8601 hinzugefügt hat, kann SimpleDateFormat eine vollständige Datumszeichenfolge nicht ordnungsgemäß analysieren, da optionale Teile nicht unterstützt werden.
Das Neuformatieren Ihrer Eingabezeichenfolge mit regulärem Ausdruck ist sicherlich eine Möglichkeit, aber die Ersetzungsregeln sind nicht so einfach wie in Ihrer Frage:
Die einfachere Lösung besteht möglicherweise darin, den Datentypkonverter in JAXB zu verwenden, da JAXB in der Lage sein muss, die ISO8601-Datumszeichenfolge gemäß der XML-Schemaspezifikation zu analysieren.
javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z")
Sie erhalten einCalendar
Objekt und können einfach getTime () verwenden, wenn Sie einDate
Objekt benötigen .Sie könnten wahrscheinlich auch Joda-Time verwenden , aber ich weiß nicht, warum Sie sich damit beschäftigen sollten.
quelle
Der Weg, der durch die Java 7-Dokumentation gesegnet ist :
Weitere Beispiele finden Sie im Abschnitt Beispiele unter SimpleDateFormat javadoc .
UPD 13.02.2020: In Java 8 gibt es eine völlig neue Möglichkeit , dies zu tun
quelle
java.time
Framework in Java 8 an, das von Joda-Time inspiriert wurde und die problematischen Klassen java.util.Date, .Calendar und SimpleDateFormat ersetzt.string1
undstring2
nicht wissen, welche Sie bekommen werden ?Okay, diese Frage ist bereits beantwortet, aber ich werde meine Antwort trotzdem fallen lassen. Es könnte jemandem helfen.
Ich habe nach einer Lösung für Android (API 7) gesucht .
javax.xml
, funktionieren unter Android API 7 nicht.Endete die Implementierung dieser einfachen Klasse. Es werden nur die gängigsten Formen von ISO 8601-Zeichenfolgen behandelt. Dies sollte jedoch in einigen Fällen ausreichen (wenn Sie sich ziemlich sicher sind, dass die Eingabe in diesem Format erfolgt).
Leistungshinweis: Ich instanziiere jedes Mal ein neues SimpleDateFormat, um einen Fehler in Android 2.1 zu vermeiden . Wenn Sie genauso erstaunt sind wie ich, sehen Sie sich dieses Rätsel an . Bei anderen Java-Engines können Sie die Instanz in einem privaten statischen Feld zwischenspeichern (um Thread-sicher zu sein, verwenden Sie ThreadLocal).
quelle
s = s.substring(0, 22) + s.substring(23);
- ich sehe den Punkt darin nichtjava.time
Die java.time-API (in Java 8 und höher integriert) erleichtert dies ein wenig.
Wenn Sie wissen, dass die Eingabe in UTC erfolgt , z. B.
Z
(für Zulu) am Ende, kann dieInstant
Klasse analysieren.Wenn Sie Ihre Eingabe eine andere sein kann , von-UTC - Offset- Werte und nicht UTC durch die angezeigte
Z
(Zulu) am Ende, verwenden Sie dieOffsetDateTime
Klasse zu parsen.Extrahieren Sie dann ein
Instant
und konvertieren Sie esjava.util.Date
durch Aufrufen in einfrom
.quelle
LocalDateTime
undZoneId
undatZone
. Dieser einfache Einzeiler wird tun:java.util.Date date = Date.from( ZonedDateTime.parse( "2014-12-12T10:39:40Z" ).toInstant() );
Date.from(Instant.parse("2014-12-12T10:39:40Z" ));
ist genug.OffsetDateTime
Nebenkommentar würde ein ausreichen, um ISO8601 zu analysieren (das keine Zeitzoneninformationen, sondern nur einen Versatz enthält).Instant
zum Parsen. Obwohl dies für diese spezielle Frage nicht ausreicht, ist es eine wichtige Unterscheidung, auf die hingewiesen werden sollte. Also habe ich ein zweites Beispiel für Code hinzugefügt. Hoppla, habe gerade bemerkt, dass dies ursprünglich nicht meine Antwort ist. Ich hoffe Adam stimmt zu.Die Jackson-Datenbindungsbibliothek verfügt auch über die ISO8601DateFormat-Klasse , die dies tut (tatsächliche Implementierung in ISO8601Utils) .
quelle
2015-08-11T13:10:00
. Ich versteheString index out of range: 19
. Wenn man sich den Code ansieht, scheint es, dass die Millisekunden und die Zeitzone angegeben werden müssen. Diese sollten optional sein.[yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh:mm]]
. Mit anderen Worten, die Millisekunden sind optional, aber die Zeitzone ist obligatorisch.new DateTime("2015-08-11T13:10:00").toDate()
tl; dr
Mit java.time
Das neue Paket java.time in Java 8 und höher wurde von Joda-Time inspiriert.
Die
OffsetDateTime
Klasse repräsentiert einen Moment auf der Zeitachse mit einem Versatz von UTC, aber keine Zeitzone.Beim Aufrufen
toString
wird eine Zeichenfolge im Standardformat ISO 8601 generiert:Um den gleichen Wert durch das Objektiv von UTC zu sehen, extrahieren Sie einen
Instant
oder passen Sie den Versatz von+01:00
bis an00:00
.…oder…
Stellen Sie bei Bedarf eine Zeitzone ein. Eine Zeitzone ist eine Historie von Offset-von-UTC- Werten für eine Region mit einer Reihe von Regeln für die Behandlung von Anomalien wie Sommerzeit (DST). Wenden Sie daher nach Möglichkeit eine Zeitzone anstelle eines bloßen Versatzes an.
Über java.time
Das java.time- Framework ist in Java 8 und höher integriert. Diese Klassen verdrängen die lästigen alten Legacy - Datum-Zeit - Klassen wie
java.util.Date
,Calendar
, &SimpleDateFormat
.Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu den Klassen java.time .
Weitere Informationen finden Sie im Oracle-Lernprogramm . Suchen Sie im Stapelüberlauf nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310 .
Sie können java.time- Objekte direkt mit Ihrer Datenbank austauschen . Verwenden Sie einen JDBC-Treiber, der mit JDBC 4.2 oder höher kompatibel ist . Keine Notwendigkeit für Zeichenfolgen, keine Notwendigkeit für
java.sql.*
Klassen.Woher bekomme ich die java.time-Klassen?
Das ThreeTen-Extra- Projekt erweitert java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen von java.time. Sie können einige nützliche Klassen hier wie finden
Interval
,YearWeek
,YearQuarter
, und mehr .quelle
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 Zeitzone ISO 8601 verwendet
quelle
Die DatatypeConverter-Lösung funktioniert nicht auf allen VMs. Folgendes funktioniert für mich:
Ich habe festgestellt, dass joda nicht sofort funktioniert (speziell für das Beispiel, das ich oben mit der Zeitzone an einem Datum angegeben habe, das gültig sein sollte).
quelle
Ich denke wir sollten verwenden
für Datum
2010-01-01T12:00:00Z
quelle
Eine andere sehr einfache Möglichkeit, ISO8601-Zeitstempel zu analysieren, ist die Verwendung von
org.apache.commons.lang.time.DateUtils
:quelle
Ab Java 8 gibt es eine völlig neue, offiziell unterstützte Möglichkeit, dies zu tun:
quelle
Z
als Versatz nachgestellt wird , müssen wir dies nicht explizit angeben. EinfachInstant i = Instant.parse(s);
. Die Zeichenfolge in der Frage hatte+01:00
, in welchem FallDateTimeFormatter.ISO_INSTANT
nicht funktioniert (zumindest nicht auf meinem Java 11).ISO_OFFSET_DATE_TIME
Datumsangaben mit Offsets formatieren, z. B.+01:00
( docs.oracle.com/javase/8/docs/api/java/time/format/… )java.time
Beachten Sie, dass Sie in Java 8 die Klasse java.time.ZonedDateTime und ihre statische
parse(CharSequence text)
Methode verwenden können.quelle
Instant
undZonedDateTime
sind hier nicht angebrachtZonedDateTime
.Die Problemumgehung für Java 7+ verwendet SimpleDateFormat:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);
Dieser Code kann das ISO8601-Format wie folgt analysieren:
2017-05-17T06:01:43.785Z
2017-05-13T02:58:21.391+01:00
Aber auf Java6
SimpleDateFormat
versteht nichtX
Zeichen und wird werfenIllegalArgumentException: Unknown pattern character 'X'
Wir müssen das ISO8601-Datum auf das Format normalisieren, das in Java 6 mit lesbar ist
SimpleDateFormat
.Die oben beschriebene Methode ersetzt [
Z
mit+0000
] oder [+01:00
mit+0100
], wenn in Java 6 ein Fehler auftritt (Sie können die Java-Version erkennen und try / catch durch die if-Anweisung ersetzen).quelle
Date
undSimpleDateFormat
sind schlecht gestaltet, verwirrend und fehlerhaft. Sie sind jetzt Legacy und werden durch die in Java 8 und höher integrierten java.time-Klassen ersetzt. Für Java 6 und Java 7 wird ein Großteil der Funktionen von java.time im ThreeTen-Backport- Projekt zurückportiert . Es ist viel besser, diese Bibliothek zu Ihrer App hinzuzufügen, als diese älteren Klassen zu verwenden. Einzeilige Lösung in Java.time:OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" )
Ich hatte das gleiche Problem und löste es mit dem folgenden Code.
Früher habe ich benutzt
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());
Aber später fand ich die Hauptursache für die Ausnahme war die
yyyy-MM-dd'T'HH:mm:ss.SSSZ
,Also habe ich benutzt
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
Es hat gut für mich funktioniert.
quelle
Sie können auch die folgende Klasse verwenden -
Link zum Java- Dokument - Hierarchie für Paket org.springframework.extensions.surf.maven.plugin.util
quelle
Java hat ein Dutzend verschiedene Möglichkeiten, eine Datums- und Uhrzeitangabe zu analysieren, wie die hervorragenden Antworten hier zeigen. Aber etwas erstaunlicherweise implementiert keine der Zeitklassen von Java ISO 8601 vollständig!
Mit Java 8 würde ich empfehlen:
Dies behandelt Beispiele sowohl in UTC als auch mit einem Versatz wie "2017-09-13T10: 36: 40Z" oder "2017-09-13T10: 36: 40 + 01: 00". Dies ist für die meisten Anwendungsfälle ausreichend.
Aber es wird nicht Beispiele wie behandeln „2017-09-13T10: 36: 40 + 01“, das ist eine gültige ISO 8601 Datum-Zeit.
Es wird auch nicht nur das Datum behandelt, z. B. "2017-09-13".
Wenn Sie damit umgehen müssen, würde ich vorschlagen, zuerst einen regulären Ausdruck zu verwenden, um die Syntax zu riechen.
Es gibt hier eine schöne Liste von ISO 8601-Beispielen mit vielen Eckfällen: https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/ I'm Keine Java-Klasse bekannt, die mit allen fertig werden könnte.
quelle
OffsetDateTime
wird tun und konzeptionell eine Datums- und Uhrzeitangabe mit einem Versatz besser abgleichen.OffsetDateTime
die Beispiele behandelt, mit denen Sie umgehenZonedDateTime
. Ich glaube, dass es keines der Beispiele behandelt, die es nicht tunZonedDateTime
. In diesem Sinne ist es keine Verbesserung (aber auch keine schlechtere). Entschuldigung, ich war nicht ganz klar.Apache Jackrabbit verwendet das ISO 8601-Format, um Daten zu speichern, und es gibt eine Hilfsklasse, um sie zu analysieren:
org.apache.jackrabbit.util.ISO8601
Kommt mit Jackrabbit-Jcr-Commons .
quelle
Wie bereits erwähnt, bietet Android keine gute Möglichkeit, das Parsen / Formatieren von ISO 8601-Daten mithilfe der im SDK enthaltenen Klassen zu unterstützen. Ich habe diesen Code mehrmals geschrieben, also habe ich endlich eine Liste erstellt, die eine DateUtils-Klasse enthält, die das Formatieren und Parsen von ISO 8601- und RFC 1123-Daten unterstützt. Das Gist enthält auch einen Testfall, der zeigt, was es unterstützt.
https://gist.github.com/mraccola/702330625fad8eebe7d3
quelle
SimpleDateFormat für JAVA 1.7 hat ein cooles Muster für das ISO 8601-Format.
Klasse SimpleDateFormat
Folgendes habe ich getan:
quelle
Z
im Format Zeichenfolge ist nicht ISO 8601 Zeitzone, sollten Sie verwendenX
(oderXX
oderXXX
), wenn Sie ISO 8601 Zeitzone wollenMach es so:
Hier ist die Ausgabe:
Mi 19.10. 15:15:36 CST 2016
quelle
Verwenden Sie string like
LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)
quelle
Ich bin überrascht, dass nicht einmal eine Java-Bibliothek alle ISO 8601-Datumsformate gemäß https://en.wikipedia.org/wiki/ISO_8601 unterstützt . Joda DateTime unterstützte die meisten von ihnen, aber nicht alle, und daher habe ich eine benutzerdefinierte Logik hinzugefügt, um alle zu behandeln. Hier ist meine Implementierung.
quelle
Ein kleiner Test, der zeigt, wie ein Datum in ISO8601 analysiert wird und dass LocalDateTime keine Sommerzeiten verarbeitet.
quelle
java.util.Date
,java.util.Calendar
undjava.text.SimpleDateFormat
sind jetzt Erbe , durch die verdrängte java.time Klassen in Java gebaut 8 und höher. Siehe Tutorial von Oracle .LocalDateTime
die Sommerzeit (DST) nicht behandelt wird, da sie überhaupt keine Zeitzone behandelt. Dafür brauchen wirZonedDateTime
. VorschlagenDate
undSimpleDateFormat
ist - IMHO schlecht.Ich hatte ein ähnliches Bedürfnis: Ich musste in der Lage sein, jedes ISO8601-konforme Datum zu analysieren, ohne vorher das genaue Format zu kennen, und ich wollte eine leichte Lösung, die auch unter Android funktioniert.
Als ich meine Bedürfnisse googelte, stolperte ich über diese Frage und bemerkte, dass AFAIU, keine Antwort vollständig meinen Bedürfnissen entsprach. Also habe ich jISO8601 entwickelt und auf Maven Central geschoben.
Fügen Sie einfach hinzu
pom.xml
:und dann können Sie loslegen:
Hoffe es hilft.
quelle
Um nur ein Datum wie dieses zu formatieren, hat das Folgende für mich in einer Java 6-basierten Anwendung funktioniert. Es gibt eine
DateFormat
KlasseJacksonThymeleafISO8601DateFormat
im Thymeleaf-Projekt, die den fehlenden Doppelpunkt einfügt:https://github.com/thymeleaf/thymeleaf/blob/40d27f44df7b52eda47d1bc6f1b3012add6098b3/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java
Ich habe es für die Kompatibilität mit dem ECMAScript-Datumsformat verwendet.
quelle
Basisfunktion mit freundlicher Genehmigung von @wrygiel.
Diese Funktion kann das ISO8601-Format in Java-Datum konvertieren, das die Versatzwerte verarbeiten kann. Gemäß der Definition von ISO 8601 kann der Offset in verschiedenen Formaten angegeben werden.
Diese Klasse verfügt über statische Methoden zum Konvertieren
Beispiel ISO8601 Strings
}}
quelle
Das schien für mich am besten zu funktionieren:
Ich musste JavaScript-Datumszeichenfolgen in Java konvertieren. Ich fand die obigen Arbeiten mit der Empfehlung. Es gab einige Beispiele mit SimpleDateFormat, die nahe beieinander lagen, aber nicht die Teilmenge zu sein schienen, wie empfohlen von:
http://www.w3.org/TR/NOTE-datetime
und unterstützt von PLIST und JavaScript Strings und so was ich brauchte.
Dies scheint die häufigste Form von ISO8601-Zeichenfolgen zu sein und eine gute Teilmenge.
Die Beispiele, die sie geben, sind:
Ich habe auch eine schnelle Version:
...
Ich habe es nicht bewertet, aber ich denke, es wird ziemlich schnell gehen. Es scheint zu funktionieren. :) :)
quelle
Ich denke, was viele Leute tun wollen, ist JSON-Datumszeichenfolgen zu analysieren. Wenn Sie zu dieser Seite gelangen, besteht eine gute Chance, dass Sie ein JavaScript-JSON-Datum in ein Java-Datum konvertieren möchten.
So zeigen Sie, wie eine JSON-Datumszeichenfolge aussieht:
Die JSON-Datumszeichenfolge lautet 2013-12-14T01: 55: 33.412Z.
Daten werden nicht von der JSON-Spezifikation abgedeckt, aber das oben genannte ist ein sehr spezifisches ISO 8601-Format, während ISO_8601 viel viel größer ist und dies nur eine Teilmenge ist, wenn auch eine sehr wichtige.
Siehe http://www.json.org Siehe http://en.wikipedia.org/wiki/ISO_8601 Siehe http://www.w3.org/TR/NOTE-datetime
Zufällig habe ich einen JSON-Parser und einen PLIST-Parser geschrieben, die beide ISO-8601 verwenden, aber nicht dieselben Bits.
Ich habe zwei Möglichkeiten geschrieben, dies für mein Projekt zu tun. Ein Standard, einer schnell.
Auch hier ist die JSON-Datumszeichenfolge eine sehr spezifische Implementierung von ISO 8601 ....
(Ich habe die andere in der anderen Antwort gepostet, die für PLIST-Daten funktionieren sollte, die ein anderes ISO 8601-Format haben.)
Das JSON-Datum lautet wie folgt:
PLIST-Dateien (ASCII non GNUNext) verwenden ebenfalls ISO 8601, jedoch keine Millisekunden. Daher sind nicht alle ISO-8601-Daten gleich. (Zumindest habe ich noch keinen gefunden, der Milis verwendet, und der Parser, den ich gesehen habe, überspringt die Zeitzone insgesamt OMG).
Nun zur schnellen Version (Sie finden sie in Boon).
Beachten Sie, dass Reflection.toCharArray unsicher verwendet, wenn verfügbar, aber standardmäßig string.toCharArray, wenn nicht.
(Sie können es aus dem Beispiel entfernen, indem Sie Reflection.toCharArray (Zeichenfolge) durch Zeichenfolge.toCharArray () ersetzen.)
Das isJsonDate wird wie folgt implementiert:
Wie auch immer ... ich vermute, dass einige Leute, die hierher kommen, nach dem JSON-Datumsstring suchen und obwohl es sich um ein ISO-8601-Datum handelt, ist es ein sehr spezifisches Datum, das eine ganz bestimmte Analyse benötigt.
Siehe https://github.com/RichardHightower/boon Boon verfügt über einen PLIST-Parser (ASCII) und einen JSON-Parser.
Der JSON-Parser ist der schnellste mir bekannte Java-JSON-Parser.
Unabhängig von den Jungs von Gatling Performance verifiziert.
https://github.com/gatling/json-parsers-benchmark
Es verfügt über den schnellsten JSON-Parser für Streams, Reader, Bytes [], char [], CharSequence (StringBuilder, CharacterBuffer) und String.
Weitere Benchmarks finden Sie unter:
https://github.com/RichardHightower/json-parsers-benchmark
quelle
Instant.parse( "2013-12-14T01:55:33.412Z" )