2015-09-28 26 views
13

Tôi muốn xác thực ngày tháng ở phía máy khách nên tôi đã viết mã sau đây. Nhưng thay vì nhận được một ngoại lệ tôi nhận được một đối tượng ngày thích hợp cho ngày 31 của chuỗi ngày tháng hai, rõ ràng là một ngày không hợp lệ.Java 8 LocalDateTime đang phân tích cú pháp ngày không hợp lệ

public class Test { 

    public static void main(String[] args) { 
     String dateFormat = "HH:mm:ss MM/dd/yyyy"; 
     String dateString = "11:30:59 02/31/2015"; 
     DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat, Locale.US); 
     try { 
      LocalDateTime date = LocalDateTime.parse(dateString, dateTimeFormatter); 
      System.out.println(date); 
     } catch (Exception e) { 
      // Throw invalid date message 
     } 
    } 
} 

Output: 2015-02-28T11: 30: 59

Có ai biết tại sao LocalDateTime được phân tích cú pháp ngày này thay vì ném một ngoại lệ.

+0

tại sao bạn lại chờ một ngoại lệ? – Andrew

+2

@AndrewTobilko, có lẽ vì ngày 31 tháng 2 không tồn tại. – aioobe

+0

Nhưng trình định dạng không biết về điều đó. – Satya

Trả lời

21

Bạn chỉ cần ResolverStyle nghiêm ngặt.

Phân tích cú pháp chuỗi văn bản xảy ra theo hai giai đoạn. Giai đoạn 1 là phân tích văn bản cơ bản theo các trường được thêm vào trình tạo. Giai đoạn 2 giải quyết các cặp giá trị trường đã phân tích cú pháp thành các đối tượng ngày và/hoặc thời gian. Kiểu này được sử dụng để kiểm soát cách pha 2, giải quyết, xảy ra.

Mẫu mã - nơi withResolverStyle(ResolverStyle.STRICT) là sự thay đổi quan trọng, cùng với việc sử dụng các uuuu hơn yyyy (nơi uuuu là "năm" và "yyyy" là "năm của thời đại", và do đó mơ hồ):

import java.time.*; 
import java.time.format.*; 
import java.util.*; 

public class Test { 

    public static void main(String[] args) { 
     String dateFormat = "HH:mm:ss MM/dd/uuuu"; 
     String dateString = "11:30:59 02/31/2015"; 
     DateTimeFormatter dateTimeFormatter = DateTimeFormatter 
      .ofPattern(dateFormat, Locale.US) 
      .withResolverStyle(ResolverStyle.STRICT); 
     try { 
      LocalDateTime date = LocalDateTime.parse(dateString, dateTimeFormatter); 
      System.out.println(date); 
     } catch (DateTimeParseException e) { 
      // Throw invalid date message 
      System.out.println("Exception was thrown"); 
     } 
    } 
} 
+3

Thay đổi yyyy thành uuuu trong chuỗi định dạng sau đó không cần phải gây rối với ERA – Palamino

+0

@Palamino: Aha! Làm tốt lắm, cảm ơn. –

0

LocalDateTime.parse sẽ chỉ ném ra một lỗi nếu String thông qua trong chứa các ký tự không hợp lệ, một số ngày vượt quá 31 hoặc tháng 12. vượt

Ví dụ, nếu bạn đổi mã của bạn như vậy:

String dateString = "11:30:59 0zz2/31/2015"; 

ngoại lệ sẽ bị ném do ký tự 'zz' không hợp lệ trong ngày đã cho. Về lý do tại sao nó 'tròn xuống' ngày để nói, rằng tôi không biết.

Nguồn: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#parse-java.lang.CharSequence-

+0

Được ghi nhận và sửa chữa Đúng thực. – jste89

2
try { 
    SimpleDateFormat df = new java.text.SimpleDateFormat("HH:mm:ss MM/dd/yyyy"); 
    df.setLenient(false); 
    System.out.println(df.parse("11:30:59 02/29/2015")); 
} catch (java.text.ParseException e) { 
    System.out.println(e); 
} 

Tôi tìm thấy một giải pháp để nhận ra ngày như một ngày hợp lệ với DateFormat.setLenient(boolean). Nếu bạn cố gắng phân tích bất kỳ ngày không hợp lệ nào, nó sẽ ném ngoại lệ phân tích cú pháp.

Edit:

Java 8, nhưng điều này sẽ nâng cao ngoại lệ nếu một tháng không phải là giữa 112, nếu một ngày là hơn 32. Chính xác là không hoạt động. Nhưng trong tháng làm việc.

try { 
TemporalAccessor ta = DateTimeFormatter.ofPattern("HH:mm:ss MM/dd/yyyy").parse("11:30:59 02/32/2015"); 
} catch (Exception e) { 
System.out.println(e); 
} 

Output:

java.time.format.DateTimeParseException: Text '11:30:59 02/32/2015' could not be 
parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 32 
+0

'SimpleDateFormat' không hoạt động với Java 8' LocalDateTime'. Tôi đang tìm một giải pháp với Java8 LocalDateTime – Zeeshan

7

Java 8 DateTimeFormatter sử dụng yyyy nghĩa YEAR_OF_ERA, và uuuu nghĩa NĂM. Bạn cần sửa đổi chuỗi mẫu của mình như sau:

String dateFormat = "HH:mm:ss MM/dd/uuuu"; 

DateTimeFormatter mặc định sử dụng kiểu phân giải SMART, nhưng bạn muốn sử dụng kiểu phân giải STRICT.Sửa đổi mã khởi dateTimeFormatter của bạn như sau:

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat, Locale.US) 
                 .withResolverStyle(ResolverStyle.STRICT); 
2

Nó không được làm tròn xuống. Tháng hai chưa bao giờ có 31 ngày và không thể sử dụng đối tượng ngày/giờ để xác thực ngày không tồn tại.

Kết quả là, nó có đầu vào không hợp lệ và cung cấp cho bạn xấp xỉ gần đúng nhất với ngày chính xác (ngày cuối cùng của tháng 2 năm đó).

SimpleDateFormat kế thừa từ DateFormat có phương thức setLenient(boolean value) trên đó. Tôi hy vọng rằng nếu bạn gọi là setLenient(true) trước khi phân tích cú pháp, có thể nó sẽ khiếu nại nhiều hơn, as detailed in the javadocs.

Các vấn đề liên quan