Ich habe mit der neuen Datumszeit-API gespielt, aber beim Ausführen:
public class Test {
public static void main(String[] args){
String dateFormatted = LocalDate.now()
.format(DateTimeFormatter
.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println(dateFormatted);
}
}
Es wirft:
Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay
at java.time.LocalDate.get0(LocalDate.java:680)
at java.time.LocalDate.getLong(LocalDate.java:659)
at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2543)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2182)
at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1745)
at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1719)
at java.time.LocalDate.format(LocalDate.java:1685)
at Test.main(Test.java:23)
Wenn ich mir den Quellcode der LocalDate-Klasse ansehe, sehe ich:
private int get0(TemporalField field) {
switch ((ChronoField) field) {
case DAY_OF_WEEK: return getDayOfWeek().getValue();
case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
case DAY_OF_MONTH: return day;
case DAY_OF_YEAR: return getDayOfYear();
case EPOCH_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'EpochDay' for get() method, use getLong() instead");
case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
case MONTH_OF_YEAR: return month;
case PROLEPTIC_MONTH: throw new UnsupportedTemporalTypeException("Invalid field 'ProlepticMonth' for get() method, use getLong() instead");
case YEAR_OF_ERA: return (year >= 1 ? year : 1 - year);
case YEAR: return year;
case ERA: return (year >= 1 ? 1 : 0);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
Wie im Dokument beschrieben:
Diese Methode erstellt einen Formatierer, der auf einem einfachen Muster aus Buchstaben und Symbolen basiert, wie in der Klassendokumentation beschrieben.
Und all diese Buchstaben sind definiert.
Warum also DateTimeFormatter.ofPattern
erlaubt uns nicht, einige Musterbuchstaben zu verwenden?
LocalDate
stellt nur ein Datum dar, keine DateTime. Also macht “HH:mm:ss” beim Formatieren von a keinen Sinn LocalDate
. Verwenden ein LocalDateTime
Angenommen, Sie möchten sowohl ein Datum als auch eine Uhrzeit darstellen.
Ich möchte der richtigen Antwort von @James_D folgende Details hinzufügen:
Hintergrund: Die meisten Datums-und-Uhrzeit-Bibliotheken (java.util.Calendar
in Java siehe auch .Net-DateTime bzw Date
in JavaScript bzw DateTime
in Perl) basieren auf dem Konzept eines universellen, universellen, einmaligen zeitlichen Typs (im Deutschen gibt es den poetischen Ausdruck “eierlegende Wollmilchsau”). In diesem Design kann es kein nicht unterstütztes Feld geben. Aber der Preis ist hoch: Viele Zeitprobleme lassen sich mit einem so unflexiblen Ansatz nicht angemessen handhaben, weil es schwierig bis unmöglich ist, einen gemeinsamen Nenner für alle Arten von zeitlichen Objekten zu finden.
JSR-310 hat einen anderen Weg gewählt, nämlich verschiedene zeitliche Typen zuzulassen, die aus typspezifischen Sätzen von unterstützten eingebauten Feldern bestehen. Die natürliche Konsequenz ist, dass nicht jedes mögliche Feld von jedem Typ unterstützt wird (und Benutzer können sogar ihre eigenen spezialisierten Felder definieren). Es ist auch möglich programmgesteuert fragen jedes Objekt des Typs TemporalAccessor
für seinen spezifischen Satz von unterstützten Feldern. Zum LocalDate
wir finden:
•DAY_OF_WEEK
•ALIGNED_DAY_OF_WEEK_IN_MONTH
•ALIGNED_DAY_OF_WEEK_IN_YEAR
•DAY_OF_MONTH
•DAY_OF_YEAR
•EPOCH_DAY
•ALIGNED_WEEK_OF_MONTH
•ALIGNED_WEEK_OF_YEAR
•MONTH_OF_YEAR
•PROLEPTIC_MONTH
•YEAR_OF_ERA
•YEAR
•ERA
Es gibt kein HOUR_OF_DAY-Feld, das das Problem erklärt UnsupportedTemporalTypeException
. Und wenn wir uns den JSR-310-Zuordnung von Mustersymbolen zu Feldern Wir sehen, dass das Symbol H dem nicht unterstützten HOUR_OF_DAY zugeordnet ist:
/** Map of letters to fields. */
private static final Map<Character, TemporalField> FIELD_MAP = new HashMap<>();
static {
FIELD_MAP.put('G', ChronoField.ERA);
FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA);
FIELD_MAP.put('u', ChronoField.YEAR);
FIELD_MAP.put('Q', IsoFields.QUARTER_OF_YEAR);
FIELD_MAP.put('q', IsoFields.QUARTER_OF_YEAR);
FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR);
FIELD_MAP.put('L', ChronoField.MONTH_OF_YEAR);
FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR);
FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH);
FIELD_MAP.put('F', ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH);
FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK);
FIELD_MAP.put('c', ChronoField.DAY_OF_WEEK);
FIELD_MAP.put('e', ChronoField.DAY_OF_WEEK);
FIELD_MAP.put('a', ChronoField.AMPM_OF_DAY);
FIELD_MAP.put('H', ChronoField.HOUR_OF_DAY);
FIELD_MAP.put('k', ChronoField.CLOCK_HOUR_OF_DAY);
FIELD_MAP.put('K', ChronoField.HOUR_OF_AMPM);
FIELD_MAP.put('h', ChronoField.CLOCK_HOUR_OF_AMPM);
FIELD_MAP.put('m', ChronoField.MINUTE_OF_HOUR);
FIELD_MAP.put('s', ChronoField.SECOND_OF_MINUTE);
FIELD_MAP.put('S', ChronoField.NANO_OF_SECOND);
FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY);
FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND);
FIELD_MAP.put('N', ChronoField.NANO_OF_DAY);
}
Diese Feldzuordnung bedeutet nicht, dass das Feld vom konkreten Typ unterstützt wird. Das Parsing erfolgt in mehreren Schritten. Die Feldzuordnung ist nur der erste Schritt. Der zweite Schritt ist dann das Parsen zu einem rohen Objekt des Typs TemporalAccessor
. Und schließlich Parsing-Delegates zum Zieltyp (hier: LocalDate
) und lassen Sie es entscheiden, ob es alle Feldwerte im geparsten Zwischenobjekt akzeptiert.
Der richtige Kurs für mich war ZonedDateTime
die sowohl Zeit als auch Zeitzone umfasst.
LocalDate
hat nicht die Zeitinformationen, also erhalten Sie a UnsupportedTemporalTypeException: Unsupported field: HourOfDay
.
Sie können verwenden LocalDateTime
aber dann haben Sie die Zeitzoneninformationen nicht. Wenn Sie also versuchen, darauf zuzugreifen (selbst mit einem der vordefinierten Formatierer), erhalten Sie eine UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds
.
Ich hatte ein ähnliches Problem mit diesem Code:
DateTimeFormatter.RFC_1123_DATE_TIME.format(new Date().toInstant())
java.time.temporal.UnsupportedTemporalTypeException: Nicht unterstütztes Feld: DayOfMonth
Ich habe es so gelöst:
DateTimeFormatter.RFC_1123_DATE_TIME.format(
ZonedDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault()))