我有一个传入字符串,它应该是一个格式为"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
来自SimpleDateFormat
直接继承的DateFormat
的JavaDoc:
默认情况下,解析是宽松的:如果输入不是该对象的格式化方法使用的形式,但仍然可以解析为日期,则解析成功。客户可以通过呼叫
setLenient(false)
来坚持严格遵守格式。
java.time
我建议您使用现代java日期和时间API java.time来进行日期工作。在特定情况下的优势包括,您需要的格式化程序已经内置,并且它确实抛出了您要求的异常。
为了演示,我使用了这种辅助方法:
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
类是一个臭名昭著的麻烦制造者。你已经发现了它的一个核心设计问题,但肯定不是唯一的问题。它所做的是:它解析了四位数的年份9450和两位数的月份52。一年有12个月,但标准设置的SimpleDateFormat
并不在乎。它将其中48个月转换为4年,并在4年后的第4个月结束。最后,4被解析为月中的某一天。忽略文本的其余部分Q
。
在我看来,你的例子展示了SimpleDateFormat
:的三个缺陷
- 对于标准设置,它是宽松,它接受无效的月份号
- 当被要求解析两个数字而只找到一个数字时,它会使用这一个数字而不报告错误
- 在解析文本之后出现不可解析文本的情况下,它也不会报告任何错误
链接
- Oracle教程:日期时间,解释如何使用java.Time
- 相关问题:SimpleDateFormat给出错误的日期而不是错误
- 现代答案
- 当str=2011/12/12aaaaaa时,SimpleDateFormat解析(字符串str(不会引发异常?
- 现代答案