Sofort zu String formatieren


227

Ich versuche, einen Instant zu einem String mit der neuen Java 8-Zeit-API und einem Muster zu formatieren:

Instant instant = ...;
String out = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(instant);

Mit dem obigen Code erhalte ich eine Ausnahme, die ein nicht unterstütztes Feld beschwert:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
    at java.time.Instant.getLong(Instant.java:608)
    at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
    ...

Antworten:


310

Zeitzone

So formatieren Sie eine Instanteine Zeitzone erforderlich ist. Ohne eine Zeitzone weiß der Formatierer nicht, wie der Moment in menschliche Datums- / Uhrzeitfelder konvertiert werden soll, und löst daher eine Ausnahme aus.

Die Zeitzone kann mit direkt zum Formatierer hinzugefügt werden withZone().

DateTimeFormatter formatter =
    DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT )
                     .withLocale( Locale.UK )
                     .withZone( ZoneId.systemDefault() );

String generieren

Verwenden Sie nun diesen Formatierer, um die String-Darstellung Ihres Instant zu generieren.

Instant instant = Instant.now();
String output = formatter.format( instant );

Zur Konsole werfen.

System.out.println("formatter: " + formatter + " with zone: " + formatter.getZone() + " and Locale: " + formatter.getLocale() );
System.out.println("instant: " + instant );
System.out.println("output: " + output );

Beim Ausführen.

formatter: Localized(SHORT,SHORT) with zone: US/Pacific and Locale: en_GB
instant: 2015-06-02T21:34:33.616Z
output: 02/06/15 14:34

50
Danke dir!! Übrigens ist die Ausnahme "nicht unterstütztes Feld", die beispielsweise auf das Jahr verweist, spektakulär stumpf. Möglicherweise sollte diese Situation erkannt und eine Ausnahme ausgelöst werden, die direkt auf die fehlende Zonen-ID im Instant verweist!
Davidbak

1
Noch seltsamer ist, wenn Sie .withZone (z. B. .withZone (ZoneId.of ("Z"))) einschließen und eine LocalDateTime formatieren, wird die Zone ignoriert! Solange .withZone () enthalten ist, kann derselbe Formatierer sowohl für Instant als auch für LocalDateTime verwendet werden, ohne die für letztere angezeigte Zeit zu beeinflussen.
Glenn

1
Warum ist es so schwierig zu akzeptieren, dass Instant eine Zeitzone hat, die GMT ist?
Koray Tugay

1
@KorayTugay Da pedantische Kommentare zu "Instant ist bereits GMT" zwar zutreffen können, sind sie bei einem ausgelösten Ausnahme-Trace alles andere als hilfreich, da das Formatieren eines Instant ohne Angabe einer Zeitzone nicht funktioniert. Es wäre schön gewesen, wenn der Formatierer standardmäßig GMT verwendet hätte, aber na ja.
Ti Strga

Dies gibt Ihnen das folgende yyyy-MM-dd hh:mm:ssFormat:DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss").withZone(ZoneId.of("Europe/Paris"));
WesternGun

39
public static void main(String[] args) {

    DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
            .withZone(ZoneId.systemDefault());

    System.out.println(DATE_TIME_FORMATTER.format(new Date().toInstant()));

}

3
Während dieser Code die Frage möglicherweise beantwortet, würde die Bereitstellung eines zusätzlichen Kontexts darüber, wie und warum das Problem gelöst wird, den langfristigen Wert der Antwort verbessern.
Alexander

1
Während dieses Code-Snippet die Frage lösen kann, hilft das Hinzufügen einer Erklärung wirklich, die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage für Leser in Zukunft beantworten und diese Personen möglicherweise die Gründe für Ihren Codevorschlag nicht kennen.
Rosário Pereira Fernandes

23
DateTimeFormatter.ISO_INSTANT.format(Instant.now())

Dies erspart Ihnen die Konvertierung in UTC. Die Zeitrahmen einiger anderer Sprachen unterstützen die Millisekunden möglicherweise nicht, daher sollten Sie dies tun

DateTimeFormatter.ISO_INSTANT.format(Instant.now().truncatedTo(ChronoUnit.SECONDS))

Was meinst du mit "Zeitrahmen einer anderen Sprache"? Wird ISO_INSTANT.format () automatisch auf Sekunden abgeschnitten?
Guangtong Shen

Einige Frameworks erwarten, dass nur die Zeit auf die Sekunden ansteigt, da sie nicht der vollständigen ISO-Konvention entsprechen und brechen, wenn Millisekunden als Teil der Eingabezeichenfolge vorhanden sind.
Archimedes Trajano

21

Die InstantKlasse enthält keine Zoneninformationen, sondern speichert den Zeitstempel nur in Millisekunden ab der UNIX-Epoche, dh ab dem 1. Januar 1070 ab UTC. Daher kann der Formatierer kein Datum drucken, da das Datum immer für eine konkrete Zeitzone gedruckt wird. Sie sollten die Zeitzone auf Formatierung einstellen und alles wird in Ordnung sein, wie folgt:

Instant instant = Instant.ofEpochMilli(92554380000L);
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.UK).withZone(ZoneOffset.UTC);
assert formatter.format(instant).equals("07/12/72 05:33");
assert instant.toString().equals("1972-12-07T05:33:00Z");

4

Wenn Sie weiterhin einen aus einem Muster erstellten Formatierer verwenden möchten, können Sie einfach LocalDateTime anstelle von Instant verwenden:

LocalDateTime datetime = LocalDateTime.now();
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(datetime)

4

Instants befinden sich bereits in UTC und haben bereits das Standard-Datumsformat JJJJ-MM-TT . Wenn Sie damit zufrieden sind und sich nicht mit Zeitzonen oder Formatierungen herumschlagen möchten, können Sie auch Folgendes tun toString():

Instant instant = Instant.now();
instant.toString()
output: 2020-02-06T18:01:55.648475Z


Willst du nicht das T und Z? (Z gibt an, dass dieses Datum UTC ist. Z steht für "Zulu" oder "Zero Hour Offset" oder UTC)):

instant.toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.663763


Willst du Millisekunden statt Nanosekunden? (Sie können es also in eine SQL-Abfrage einfügen):

instant.truncatedTo(ChronoUnit.MILLIS).toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.664

etc.


-3
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String text = date.toString(formatter);
LocalDate date = LocalDate.parse(text, formatter);

Ich glaube, dies könnte helfen. Möglicherweise müssen Sie eine Art localdate-Variation anstelle von Instant verwenden

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.