Định dạng ngày bằng API ngày giờ mới


118

Tôi đang chơi với API ngày giờ mới nhưng khi chạy cái này:

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

Nó ném:

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)

Khi nhìn vào mã nguồn của lớp LocalDate, tôi thấy:

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

Như nó được mô tả trong tài liệu:

Phương pháp này sẽ tạo một định dạng dựa trên một mẫu đơn giản của các chữ cái và ký hiệu như được mô tả trong tài liệu lớp.

Và tất cả các chữ cái này được xác định .

Vậy tại sao DateTimeFormatter.ofPatternkhông cho phép chúng ta sử dụng một số mẫu tự?

Câu trả lời:


219

LocalDatechỉ đại diện cho một ngày, không phải một DateTime. Vì vậy, "HH: mm: ss" không có ý nghĩa gì khi định dạng a LocalDate. Sử dụng LocalDateTimethay thế, giả sử bạn muốn đại diện cho cả ngày và giờ.


3
Làm thế nào tôi có thể upvote câu trả lời này và downvote thực tế có cả một LOCALDATE và một đối tượng LocalDateTime ...
Xials

Tôi chỉ muốn làm việc với LocalTime, làm cách nào để bạn thực hiện định dạng mà không gặp phải ngoại lệ nàyjava.time.temporal.UnsupportedTemporalTypeException: Unsupported field: DayOfWeek
samuel owino

Đừng DateTimeFormatter.ofPattern("HH:mm:ss")
bận

36

Tôi muốn thêm các chi tiết sau vào câu trả lời chính xác của @James_D:

Thông tin cơ bản: Hầu hết các thư viện ngày và giờ ( java.util.Calendartrong Java, xem thêm .Net-DateTime hoặc Datetrong JavaScript hoặc DateTimetrong Perl) đều dựa trên khái niệm về kiểu thời gian duy nhất đa mục đích phổ quát (trong tiếng Đức có thành ngữ thơ " eierlegende Wollmilchsau "). Trong thiết kế này không thể có trường không được hỗ trợ. Nhưng cái giá phải trả cao: Nhiều vấn đề về thời gian không thể được xử lý thỏa đáng với một cách tiếp cận không linh hoạt như vậy vì khó có thể tìm ra một mẫu số chung cho tất cả các loại vật thể thời gian.

JSR-310 đã chọn một cách khác , cụ thể là cho phép các kiểu thời gian khác nhau bao gồm các tập hợp các trường tích hợp được hỗ trợ theo kiểu cụ thể. Hệ quả tự nhiên là không phải mọi trường có thể được hỗ trợ bởi mọi loại (và người dùng thậm chí có thể xác định các trường chuyên biệt của riêng họ). Cũng có thể lập trình yêu cầu mọi đối tượng thuộc loại TemporalAccessorcho tập hợp các trường được hỗ trợ cụ thể của nó. Đối với LocalDatechúng tôi tìm thấy:

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 

Không có trường HOUR_OF_DAY nào giải thích sự cố của UnsupportedTemporalTypeException. Và nếu chúng ta nhìn vào JSR-310- ánh xạ các biểu tượng mẫu vào các trường, chúng ta thấy rằng biểu tượng H được ánh xạ tới HOUR_OF_DAY không được hỗ trợ:

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

Ánh xạ trường này không có nghĩa là trường được hỗ trợ bởi kiểu cụ thể. Quá trình phân tích cú pháp diễn ra theo một số bước. Lập bản đồ thực địa chỉ là bước đầu tiên. Bước thứ hai sau đó là phân tích cú pháp thành một đối tượng thô của kiểu TemporalAccessor. Và cuối cùng phân tích cú pháp các đại biểu cho kiểu đích (tại đây LocalDate:) và để nó quyết định xem nó có chấp nhận tất cả các giá trị trường trong đối tượng trung gian được phân tích cú pháp hay không.


4
vi.wiktionary.org/wiki/eierlegende_Wollmilchsau (nghĩa đen là “len đẻ trứng-sữa-nái”) Một thiết bị hoặc người tất cả trong một chỉ có (hoặc tuyên bố là có) các thuộc tính tích cực và có thể (hoặc cố gắng) thực hiện công việc của một số công cụ chuyên dụng. :-)
Trevor Robinson

6

Lớp học phù hợp với tôi ZonedDateTimebao gồm cả Múi giờ và Múi giờ.

LocalDatekhông có thông tin Thời gian để bạn nhận được một UnsupportedTemporalTypeException: Unsupported field: HourOfDay.

Bạn có thể sử dụng LocalDateTimenhưng khi đó bạn không có thông tin Múi giờ, vì vậy nếu bạn cố gắng truy cập thông tin đó (thậm chí bằng cách sử dụng một trong các định dạng được xác định trước), bạn sẽ nhận được một UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.