Java 8: erstellen von DateTimeFormatter mit milli -, Mikro-oder nano-Sekunden?
Ich brauchen, um das Formatierungsprogramm für die Analyse der Zeitstempel optional mit milli -, Mikro-oder nano-Bruchteile der Sekunde.
Zum Beispiel, für meine Bedürfnisse sehe ich folgende Möglichkeit:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.BASIC_ISO_DATE)
.appendLiteral('-')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendOffset("+HH:mm", "Z")
.toFormatter();
Oder es ist auch möglich, mit appendFraction(field, minWidth, maxWidth, decimalPoint)
.
Jedoch in diesen Fällen wird es möglich sein, zu analysieren Zeitstempel mit einer beliebigen Anzahl von Dezimalstellen (bis zu 9 oder maxWidth). Wie das zu erreichen ist, dass wir analysieren können (Optional) nur 3, 6 oder 9 zahlen nach dem Komma?
Sollte es möglich sein, um eine Analyse der folgenden Zeit Teile:
HH:mm:ss.SSS
HH:mm:ss.SSSSSS
HH:mm:ss.SSSSSSSSS
Aber unmöglich zu analysieren: HH:mm:ss.SSSS
.
- Glaube nicht, dass Sie können, aber warum tun Sie kümmern? Was wäre falsch mit der Annahme z.B. 4 Nachkommastellen? Es ist vollkommen gültig nach ISO-8601.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Können Sie den optionalen Abschnitten, die Muster (getrennt durch
[]
), und erstellen Sie 3 optionale Abschnitte: 1 für die 9 Ziffern, eine für die 6 Ziffern und 3 Ziffern.Laut
DateTimeFormatterBuilder
docs, können Sie dieS
Muster (das entspricht NANO_OF_SECOND Feld):In der alten API (
SimpleDateFormat
),S
wird das Muster verwendet, für Millisekunden, aber in der neuen API-es wurde geändert, um Nanosekunden.Also der formatter erstellt werden wie diese:
Einige tests:
Ausgabe:
Hinweise:
Diese Instanz von
DateTimeFormatter
ist nicht gut für Formatierung, denn es druckt alle optionalen Abschnitten, die (so die Nanosekunde gedruckt werden 3-mal):Also, wenn Sie wollen, um Ihre Daten in einem anderen format, erwägen, einen anderen
DateTimeFormatter
.In Ihrem code, den Sie verwenden
DateTimeFormatter.ISO_LOCAL_TIME
. Nach javadoc, in diesem formatter die Sekunden sind optional. Wenn Sie wollen, um das gleiche Verhalten, nur die Zeit ändern Muster:Den
[]
- Muster ist eine nette Abkürzung, um optionale Abschnitte, aber Sie können auch erstellen Sie mit HilfeoptionalStart()
mitappendFraction()
:Diese formatter funktioniert auf exakt die gleiche Weise wie die erste erstellt mit
[]
Muster.Nebenwirkung
Als @SeanVanGorder bemerkt in seinem Kommentar, ist dieses Formatierungsprogramm hat den Nebeneffekt, die Annahme mehrerer Muster für die Nanosekunden-Bereich, aber es funktioniert nur, wenn die Werte gleich sind:
Alle Zeilen der obigen Ausgabe
2016-12-01T10:30:45.123Z
, aber beachten Sie, dass Sie akzeptieren alle optionalen Werte (wie.123000000.123
). Die Werte sind die gleichen, die Analyse wird durchgeführt, ohne Fehler.Wenn die Werte unterschiedlich sind, obwohl, es gibt eine Ausnahme:
Wenn dieses Verhalten nicht gewünscht ist, die einzige alternative ist, erstellen viele verschiedene formatter (für jeden Fall) und machen Sie ein
for
Schleife, bis Sie einen gültigen Analysierte Wert (sehr ähnlich diese Antwort).Zuerst erstellte ich eine Methode erhält eine Liste von
DateTimeFormatter
's und einTemporalQuery
zu konvertieren, analysiert string, der für jedes Objekt, das Sie wollen:Nun, die Sie gerade brauchen, um das Formatierer und Sie in den
parse
Methode:Hinweis, dass ich die Methode Referenz
OffsetDateTime::from
alsTemporalQuery
, aber Sie können es ändern, um jede Abfrage, die Sie benötigen..123456.123
), aber nach Tests sieht es aus wie DateTimeFormatter nicht akzeptieren mehrere verschiedene Werte für den gleichen Bereich. Es akzeptieren.123000.123
aber nicht, aber ich bezweifle, dass das ein Problem..123000000.123000.123
oder.123000000.123
). Wenn der Eingang ist wie.123000.456
, wirft er eine exception. Ich denke, das kann vermieden werden, indem die Validierung der input - oder vielleicht brauchen Sie nicht, wenn Sie sicherstellen, dass die input-strings werden korrekt erzeugt (OP hat nicht erläutert, wie der inputs generiert werden, aber ich nehme an, Sie kommen von Datum/Zeit-Objekte). Trotzdem Stimme ich zu, dass ist ein kleines Problem. Danke!DateTimeFormatter
unterstützt nur die Breite variiert, so dass dies nicht möglich wäre, mit einer einzigen Instanz. Man könnte die 3 separaten Formatierer mit.appendFraction(NANO_OF_SECOND, #, #, true)
wobei # 3, 6, oder 9. Dann versuchen Sie in der Reihenfolge, ignoriertDateTimeParseException
bis die Letzte:Andere Möglichkeit wäre die überprüfung der Eingabe mit einem regulären Ausdruck zuerst so etwas wie
text.matches("[^.]+(.+\\.(\\d{3}|\\d{6}|\\d{9})\\b.*)?")
.