Formatieren Sie ein Datum mit der neuen Datums- / Uhrzeit-API


118

Ich habe mit der neuen Datums- / Uhrzeit-API gespielt, aber als ich diese ausführte:

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 basierend auf einem einfachen Muster aus Buchstaben und Symbolen, wie in der Klassendokumentation beschrieben.

Und all diese Buchstaben sind definiert .

Warum dürfen DateTimeFormatter.ofPatternwir also keine Musterbuchstaben verwenden?

Antworten:


218

LocalDaterepräsentiert nur ein Datum, keine DateTime. "HH: mm: ss" macht also beim Formatieren von a keinen Sinn LocalDate. Verwenden Sie LocalDateTimestattdessen a, vorausgesetzt, Sie möchten sowohl ein Datum als auch eine Uhrzeit darstellen.


3
Wie kann ich diese Antwort positiv und negativ bewerten, da es sowohl ein LocalDate- als auch ein LocalDateTime-Objekt gibt ...
Xials

Ich würde mit Localtime nur Arbeit mögen, wie Sie ohne Sie führen die Formatierung in diese Ausnahme ausgeführtjava.time.temporal.UnsupportedTemporalTypeException: Unsupported field: DayOfWeek
samuel Owino

DateTimeFormatter.ofPattern("HH:mm:ss")
Egal

36

Ich möchte der richtigen Antwort von @James_D folgende Details hinzufügen:

Hintergrund: Die meisten Datums- und java.util.CalendarZeitbibliotheken ( in Java siehe auch .Net-DateTime oder Datein JavaScript oder DateTimein Perl) basieren auf dem Konzept eines universellen, universellen, einzigartigen Zeittyps (auf Deutsch gibt es den poetischen Ausdruck " eierlegende Wollmilchsau "). In diesem Design darf es kein nicht unterstütztes Feld geben. Aber der Preis ist hoch: Viele Zeitprobleme können mit einem solch unflexiblen Ansatz nicht angemessen behandelt werden, da 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 unterstützter integrierter Felder bestehen. Die natürliche Folge ist, dass nicht jedes mögliche Feld von jedem Typ unterstützt wird (und Benutzer sogar ihre eigenen Spezialfelder definieren können). Es ist auch möglich , jedes Objekt des Typs programmgesteuertTemporalAccessor nach seinem spezifischen Satz unterstützter Felder zu fragen . Denn LocalDatewir 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 von erklärt UnsupportedTemporalTypeException. Und wenn wir uns die JSR-310- Zuordnung von Mustersymbolen zu Feldern ansehen, sehen wir, dass das Symbol H nicht unterstütztem 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 Parsen erfolgt in mehreren Schritten. Die Feldzuordnung ist nur der erste Schritt. Der zweite Schritt ist dann das Parsen auf ein Rohobjekt vom Typ TemporalAccessor. Und schließlich analysieren Sie die Delegaten auf den Zieltyp (hier :) LocalDateund lassen Sie ihn entscheiden, ob alle Feldwerte im analysierten Zwischenobjekt akzeptiert werden.


4
en.wiktionary.org/wiki/eierlegende_Wollmilchsau (wörtlich „ Wollmilch -Sau“) Ein All-in-One-Gerät oder eine Person, die nur positive Eigenschaften hat (oder zu haben behauptet) und die dies kann (oder versucht) Arbeiten Sie mit mehreren Spezialwerkzeugen. :-)
Trevor Robinson

6

Die richtige Klasse für mich war ZonedDateTimesowohl die Zeit als auch die Zeitzone.

LocalDatehat nicht die Zeitinformationen, so dass Sie eine erhalten UnsupportedTemporalTypeException: Unsupported field: HourOfDay.

Sie können verwenden, LocalDateTimeaber dann haben Sie nicht die Zeitzoneninformationen. Wenn Sie also versuchen, darauf zuzugreifen (selbst wenn Sie einen der vordefinierten Formatierer verwenden), erhalten Sie eine UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds.

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.