Format tanggal menggunakan API waktu tanggal baru

118

Saya bermain dengan API waktu tanggal baru tetapi ketika menjalankan ini:

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);
    }
}

Ini melempar:

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)

Saat melihat kode sumber kelas LocalDate, saya melihat:

  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);
    }

Seperti yang dijelaskan di dokumen:

Metode ini akan membuat pemformat berdasarkan pola huruf dan simbol sederhana seperti yang dijelaskan dalam dokumentasi kelas.

Dan semua huruf ini telah ditentukan .

Jadi mengapa DateTimeFormatter.ofPatterntidak mengizinkan kami untuk menggunakan beberapa huruf pola?

pengguna2336315
sumber

Jawaban:

219

LocalDatehanya mewakili tanggal, bukan DateTime. Jadi "HH: mm: ss" tidak masuk akal saat memformat file LocalDate. Gunakan a LocalDateTimesebagai gantinya, dengan asumsi Anda ingin mewakili tanggal dan waktu.

James_D
sumber
3
Bagaimana saya bisa memberi suara positif pada jawaban ini dan memberi suara negatif pada fakta bahwa ada objek LocalDate dan LocalDateTime ...
Xials
Saya hanya ingin bekerja dengan LocalTime, bagaimana Anda melakukan pemformatan tanpa mengalami pengecualian inijava.time.temporal.UnsupportedTemporalTypeException: Unsupported field: DayOfWeek
samuel owino
Tidak apa-apa: ini berhasilDateTimeFormatter.ofPattern("HH:mm:ss")
samuel owino
36

Saya ingin menambahkan detail berikut ke jawaban yang benar dari @James_D:

Latar belakang: Kebanyakan pustaka tanggal dan waktu ( java.util.Calendardi Java, lihat juga .Net-DateTime atau Datedi JavaScript atau DateTimedi Perl) didasarkan pada konsep tipe temporal unik serbaguna universal (dalam bahasa Jerman ada ungkapan puitis " eierlegende Wollmilchsau "). Dalam desain ini tidak boleh ada bidang yang tidak didukung. Tetapi harganya mahal: Banyak masalah waktu tidak dapat ditangani secara memadai dengan pendekatan yang tidak fleksibel karena sulit untuk tidak mungkin menemukan penyebut yang sama untuk semua jenis objek temporal.

JSR-310 telah memilih cara lain , yaitu untuk memungkinkan tipe temporal berbeda yang terdiri dari set khusus tipe bidang built-in yang didukung. Konsekuensi alami adalah tidak setiap bidang yang memungkinkan didukung oleh setiap jenis (dan pengguna bahkan dapat menentukan bidang khusus mereka sendiri). Dimungkinkan juga untuk secara terprogram meminta setiap objek jenis TemporalAccessoruntuk kumpulan spesifik bidang yang didukung. Karena LocalDatekami menemukan:

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 

Tidak ada bidang HOUR_OF_DAY yang menjelaskan masalah UnsupportedTemporalTypeException. Dan jika kita melihat JSR-310- pemetaan simbol pola ke bidang, kita melihat bahwa simbol H dipetakan ke HOUR_OF_DAY yang tidak didukung:

/** 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);    
}

Pemetaan lapangan ini tidak berarti bahwa lapangan tersebut didukung oleh jenis beton. Penguraian terjadi dalam beberapa langkah. Pemetaan lapangan hanyalah langkah pertama. Langkah kedua adalah mem-parsing menjadi objek mentah bertipe TemporalAccessor. Dan terakhir, parsing delegasi ke jenis target (di sini LocalDate:) dan biarkan memutuskan apakah menerima semua nilai bidang dalam objek perantara yang diurai.

Meno Hochschild
sumber
4
en.wiktionary.org/wiki/eierlegende_Wollmilchsau (secara harfiah berarti “telur-bertelur-wol-susu-tabur”) Perangkat all-in-one atau orang yang memiliki (atau mengklaim memiliki) hanya atribut positif dan yang dapat (atau mencoba) melakukan pekerjaan beberapa alat khusus. :-)
Trevor Robinson
6

Kelas yang tepat bagi saya adalah ZonedDateTimeyang mencakup Zona Waktu dan Waktu.

LocalDatetidak memiliki informasi Waktu sehingga Anda mendapatkan a UnsupportedTemporalTypeException: Unsupported field: HourOfDay.

Anda dapat menggunakan LocalDateTimetetapi kemudian Anda tidak memiliki informasi Zona Waktu jadi jika Anda mencoba mengaksesnya (bahkan dengan menggunakan salah satu pemformat yang telah ditentukan) Anda akan mendapatkan UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds.

isapir
sumber