2014-10-15 24 views
10

Tôi gặp vấn đề đơn giản: Tôi muốn phân tích cú pháp các chuỗi Java theo định dạng "yyyyMMdd" nghiêm ngặt, sao cho "19800229" là ngày hợp lệ, nhưng "19820229" thì không. Giả sử đây là những ngày AD từ lịch Gregorian bình thường.Sử dụng Java 8 DateTimeFormatter mới để phân tích cú pháp ngày tháng

Tôi đang cố gắng sử dụng gói java.time mới từ JDK 8 để giải quyết vấn đề này, nhưng điều này chứng tỏ phức tạp hơn mong đợi. mã hiện tại của tôi là:

private static final DateTimeFormatter FORMAT = DateTimeFormatter 
     .ofPattern("yyyyMMdd").withChronology(IsoChronology.INSTANCE) 
     .withResolverStyle(STRICT); 

public static LocalDate parse(String yyyyMMdd) { 
    return LocalDate.parse(yyyyMMdd, FORMAT); 
} 

Tuy nhiên, phân tích một ngày hợp lệ như "19.800.228" sản xuất những gì để cho tôi một lỗi không thể hiểu được là:

java.time.format.DateTimeParseException: Text '19820228' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {MonthOfYear=2, DayOfMonth=28, YearOfEra=1982},ISO of type java.time.format.Parsed

Làm thế nào để sử dụng java.time.format.DateTimeFormatter để giải quyết trường hợp sử dụng đơn giản của tôi ?

Trả lời

2

Tôi đang chỉnh sửa để giới hạn loại chuỗi nào sẽ được coi là hợp lệ bằng cách sử dụng trình định dạng tùy chỉnh được tạo bằng DateTimeFormatterBuilder.

public class DateFormmaterTest { 

    static DateTimeFormatter CUSTOM_BASIC_ISO_DATE = new DateTimeFormatterBuilder() 
      .parseCaseInsensitive().appendValue(YEAR, 4) 
      .appendValue(MONTH_OF_YEAR, 2).appendValue(DAY_OF_MONTH, 2) 
      .optionalStart().toFormatter() 
      .withResolverStyle(ResolverStyle.STRICT) 
      .withChronology(IsoChronology.INSTANCE); 

    public static void main(String[] args) { 

     LocalDate date1 = LocalDate.parse("19800228-5000", 
       CUSTOM_BASIC_ISO_DATE); 

     System.out.println(date1); 

    } 
} 

2/29/1982 là không hợp lệ và sẽ ném những điều sau:

Caused by: java.time.DateTimeException: Invalid date 'February 29' as '1982' is not a leap year 
    at java.time.LocalDate.create(LocalDate.java:429) 

Một ngày 19.800.228-5000 sẽ làm việc với BASIC_ISO_DATE vì nó cho phép các tùy chọn bù đắp mà bạn không muốn cho phép . formatter CUSTOM_BASIC_ISO_DATE của tôi sẽ không cho phép điều đó và ném như sau:

Exception in thread "main" java.time.format.DateTimeParseException: Text '19800228-5000' could not be parsed, unparsed text found at index 8. 

Lưu ý, nếu bạn chắc chắn về độ dài chuỗi, yyyyMMdd sau đó bạn có thể luôn luôn làm việc với chuỗi 8 ký tự đầu tiên để phủ nhận sự cần thiết của resolver . Tuy nhiên đó là hai điều khác nhau. Trình phân giải sẽ gắn cờ các định dạng ngày không hợp lệ trên đầu vào và chuỗi con dĩ nhiên sẽ tách các ký tự thừa ra ngoài.

+0

Cảm ơn @Tech Trip. Xin lỗi tôi có nghĩa là 2/29 trong cả hai trường hợp, như bạn đã chỉ ra. Lý do tôi tránh 'DateTimeFormatter.BASIC_ISO_DATE' là nó có phần tùy chọn mà tôi không muốn phân tích cú pháp. Tôi có thể tạo một trình định dạng tương đương không có phần tùy chọn không? – 0xbe5077ed

+0

Tôi đã sửa đổi câu trả lời để xem xét nhận xét cuối cùng của bạn. Xin vui lòng cho nó một cái nhìn! – TechTrip

+0

Đủ tốt, @Tech Trip. Đó là những gì tôi phát hiện ra là tốt. Lưu ý rằng bạn có thể loại bỏ 'parseCaseInsensitive()' - không cần thiết vì yyyyMMdd không có vấn đề về trường hợp - và 'startOptional()' vì bạn không bắt đầu bất cứ điều gì tùy chọn. – 0xbe5077ed

1

Hãy thử sử dụng định dạng "uuuuMMdd" để thay thế.

12

Java 8 sử dụng uuuu cho năm, không phải yyyy. Trong Java 8, yyyy có nghĩa là "năm của thời đại" (BC hoặc AD) và thông báo lỗi than phiền rằng MonthOfYear, DayOfMonth và YearOfEra là không đủ thông tin để xây dựng ngày vì thời đại không được biết đến.

Để khắc phục điều đó, hãy sử dụng uuuu trong chuỗi định dạng của bạn, ví dụ: DateTimeFormatter.ofPattern("uuuuMMdd")

Hoặc nếu bạn muốn tiếp tục sử dụng yyyy, bạn có thể đặt thời đại mặc định, ví dụ:

new DateTimeFormatterBuilder() 
     .appendPattern("yyyyMMdd") 
     .parseDefaulting(ChronoField.ERA, 1 /* era is AD */) 
     .toFormatter() 
Các vấn đề liên quan