簡體   English   中英

使 SimpleDateFormat.parse() 在無效日期時失敗(例如,月份大於 12)

[英]Make SimpleDateFormat.parse() fail on invalid dates (e.g. month is greater than 12)

我正在使用java.text.SimpleDateFormat來解析"yyyyMMdd"形式的字符串。

如果我嘗試解析一個月份大於 12 的字符串,它不會失敗,而是會轉到下一年。 完全可運行的重現:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ParseDateTest {

    public static void main(String[] args) throws ParseException {

        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        Date result = format.parse("20091504"); // <- should not be a valid date!
        System.out.println(result); // prints Thu Mar 04 00:00:00 CST 2010
    }
 }

我寧願拋出ParseException

是否有任何非 hacky 方式強制異常發生? 我的意思是,我不想手動檢查月份是否大於 12。這有點荒謬。

感謝您的任何建議。

注意:我已經知道 Joda Time,但我需要在沒有外部庫的普通 JDK 中完成此操作。

你需要讓它變得不寬容 因此,

format.setLenient(false);

應該這樣做。

您可以使用 Java 8 時間 API。 例如,如果您使用值為15的月份:

String strDate = "20091504";
TemporalAccessor ta = DateTimeFormatter.ofPattern("yyyyMMdd").parse(strDate);

你會直接有異常

Exception in thread "main" java.time.format.DateTimeParseException:
Text '20091504' could not be parsed:
Invalid value for MonthOfYear (valid values 1 - 12): 15

通過使用 Java 8 LocalDate你可以這樣寫,

String strDate = "20091504";
LocalDate date1 = LocalDate.parse(strDate, DateTimeFormatter.BASIC_ISO_DATE);
System.out.println(date1);

這是解析過程中拋出的異常

Exception in thread "main" java.time.format.DateTimeParseException: Text '20091504' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 15
at java.time.format.DateTimeFormatter.createError(Unknown Source)
at java.time.format.DateTimeFormatter.parse(Unknown Source)
at java.time.LocalDate.parse(Unknown Source)
at com.katte.infa.DateFormatDemo.main(DateFormatDemo.java:22)

Caused by: java.time.DateTimeException: Invalid value for MonthOfYear (valid values 1 - 12): 15
at java.time.temporal.ValueRange.checkValidIntValue(Unknown Source)
at java.time.temporal.ChronoField.checkValidIntValue(Unknown Source)
at java.time.chrono.IsoChronology.resolveYMD(Unknown Source)
at java.time.chrono.IsoChronology.resolveYMD(Unknown Source)
at java.time.chrono.AbstractChronology.resolveDate(Unknown Source)
at java.time.chrono.IsoChronology.resolveDate(Unknown Source)
at java.time.chrono.IsoChronology.resolveDate(Unknown Source)
at java.time.format.Parsed.resolveDateFields(Unknown Source)
at java.time.format.Parsed.resolveFields(Unknown Source)
at java.time.format.Parsed.resolve(Unknown Source)
at java.time.format.DateTimeParseContext.toResolved(Unknown Source)
at java.time.format.DateTimeFormatter.parseResolved0(Unknown Source)
... 3 more

java.time

使用現代日期時間 API java.time已經有兩個答案( 12 )。 雖然我強烈建議使用第一個,但我寫這個答案是為了澄清兩個重要事實:

  1. 第一個使用預定義的格式化程序DateTimeFormatter.BASIC_ISO_DATE 請務必注意,所有預定義的格式化程序都使用ResolverStyle#STRICT ,因此,這是驗證日期字符串的完美模式。
  2. 第二個使用自定義DateTimeFormatter ,默認情況下,所有自定義DateTimeFormatter使用ResolverStyle#SMART 這意味着此解決方案可以正確驗證20091504 ,因為月份的范圍是從 1 到 12,它無法以所需的方式驗證20090230之類的字符串。 由於月日的范圍可以從 1 到 31,因此解析器會將其自動更正為2009-02-28

如何使用自定義格式化程序嚴格驗證日期字符串?

使用DateTimeFormatter#withResolverStyle.STRICT如下所示:

class Main {
    public static void main(String[] args) {
        String strDate = "20090230";

        DateTimeFormatter parserDefaultResStyl = DateTimeFormatter.ofPattern("yyyyMMdd");
        DateTimeFormatter parserStrictResStyl = DateTimeFormatter.ofPattern("yyyyMMdd")
                .withResolverStyle(ResolverStyle.STRICT);

        System.out.println(LocalDate.parse(strDate, parserDefaultResStyl));

        try {
            System.out.println(LocalDate.parse(strDate, parserStrictResStyl));
        } catch (DateTimeException e) {
            System.out.println(e.getMessage());
            // throw e;
        }
    }
}

輸出

2009-02-28
Text '20090230' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {YearOfEra=2009, DayOfMonth=30, MonthOfYear=2},ISO of type java.time.format.Parsed

Trail 了解有關現代日期時間 API 的更多信息:日期時間

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM