在 JAVA 中将无效字符串传递给 SimpleDateFormat 时引发异常

Raise exception when invalid string is passed to SimpleDateFormat in JAVA

我有一个传入字符串,它应该是格式为 "yyyyMMdd" 的日期。(例如今天的日期 - 20200507) 但有时输入字符串可能是无效格式,日期解析器应该给出异常(解析异常),但它不会返回日期对象。

示例代码,以防字符串错误或字母数字如下所示:

class Demo {
public static void main(String args[]) throws Exception {
    String inputString = "9450524Q";
    SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH);
    System.out.println(formatter.parse(inputString));
}}

输出:

Tue Apr 04 00:00:00 IST 9454

来自 DateFormat 的 JavaDoc,SimpleDateFormat 直接继承自:

By default, parsing is lenient: If the input is not in the form used by this object's format method but can still be parsed as a date, then the parse succeeds. Clients may insist on strict adherence to the format by calling setLenient(false).

java.time

我建议您使用 java.time,现代 Java 日期和时间 API,用于约会工作。在您的特定情况下的优势包括您需要的格式化程序已经内置并且它确实会抛出您要求的异常。

为了演示,我使用了这个辅助方法:

public static void tryToParse(String dateString) {
    try {
        LocalDate date
                = LocalDate.parse(dateString, DateTimeFormatter.BASIC_ISO_DATE);
        System.out.println(dateString + " -> " + date);
    } catch (DateTimeParseException dtpe) {
        System.out.println(dateString + ": " + dtpe.getMessage());
    }
}

尝试一下:

    // Valid date
    tryToParse("20200507");
    // Invalid date value
    tryToParse("20210229");
    // Text after date
    tryToParse("20200623Q");
    // Example from question
    tryToParse("9450524Q");

输出为:

20200507 -> 2020-05-07
20210229: Text '20210229' could not be parsed: Invalid date 'February 29' as '2021' is not a leap year
20200623Q: Text '20200623Q' could not be parsed, unparsed text found at index 8
9450524Q: Text '9450524Q' could not be parsed at index 6

还请欣赏准确有用的异常消息。最后一个案例发生的事情是:年 9450 和月 52 被解析,但由于 4Q 不是有效的两位数日期,因此抛出异常(在验证 52 是否为有效月份之前)。

您的代码中发生了什么

SimpleDateFormat class 是臭名昭著的麻烦制造者。您发现了它的一个核心设计问题,但肯定不是唯一的问题。它所做的是:它解析了 4 位数的年份 9450 和两位数的月份 52。一年有 12 个月,但是 SimpleDateFormat 与标准设置无关。它将 48 个月转换为 4 年,并在 4 年后的第 4 个月结束。最后 4 被解析为一个月中的第几天。文本的其余部分 Q 将被忽略。

在我看来,您的示例表现出 SimpleDateFormat 的三个缺陷:

  1. 标准设置是宽松,它接受无效的月份数。
  2. 当要求解析两位数但只找到一位数时,它以该一位数结算而不报告错误。
  3. 在解析后的文本无法解析的情况下,它也不会报告任何错误。

链接

  • Oracle tutorial: Date Time 解释如何使用 java.time.
  • 相关问题:
    • SimpleDateFormat giving wrong date instead of error
      • Modern answer
    • SimpleDateFormat parse(string str) doesn't throw an exception when str = 2011/12/12aaaaaaaaa?
      • Modern answer