据我所知,为了正确验证日期字符串,必须使DateFormat实例非宽松,以便从格式错误的日期获取所有ParseExceptions。但请考虑
String dubiousDate = "2014-04-01";
DateFormat sdf = new SimpleDateFormat( "yyyyMMdd");
Date d;
try {
d = sdf.parse( dubiousDate);
System.out.println( dubiousDate + " -> " + d);
} catch ( ParseException e) {
e.printStackTrace();
System.err.println( dubiousDate + " failed");
}
这将给出
2014-04-01 - > 2013年12月4日星期三00:00:00 CET
现在我可以理解,宽大的日历试图很好并接受有趣的负数,但这种解释看起来像-01被视为月份,即使它出现在最后,日期也是如此。 -04个月变为04天,减去忽略。
在宽大处理中,为什么这对任何人都有意义?
答案 0 :(得分:3)
我看到另一种可能的解释:
在yyyyMMdd模式中,月份部分仅限于两个字符,因为不同数字字段之间没有分隔符。因此,“ - 0”将被视为月份,仅为零,比去年12月份的一个月产生去年12月。
在“解析”假月之后,日期部分在第二个减去字符之前停止“4”。结果是12月4日。
最后,剩下的字符“-01”被忽略了。这是类SimpleDateFormat
关于如何处理非数字尾随字符的典型情况,例如,请参阅以下代码:
String dubiousDate = "2014-04-01xyz";
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d;
try {
d = sdf.parse(dubiousDate);
System.out.println(dubiousDate + " -> " + d);
// output: Tue Apr 01 00:00:00 CEST 2014
} catch (ParseException e) {
e.printStackTrace();
System.err.println(dubiousDate + " failed");
}
作为拇指规则,只有两个相等的符号字符MM或dd,解析器最多只能消耗两个字符(如果找到数字)。
关于Java 8的一些研究:
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
builder.parseLenient();
builder.append(DateTimeFormatter.ofPattern("yyyyMMdd"));
DateTimeFormatter dtf = builder.toFormatter();
String dubiousDate = "2014-04-01";
LocalDate date = LocalDate.parse(dubiousDate, dtf);
System.out.println(date);
根据JDK-8文档,以这种方式构造的格式化程序应该表现得很宽松,但遗憾的是仍然会抛出异常:
“线程中的异常”主“java.time.format.DateTimeParseException:无法在索引3处解析文本'2014-04-01'”
最佳选择是宽松的 - 从理论上讲 - 如果解析器只是忽略了减号。但显然这对JSR-310来说是不可能的(仍然太严格)。好吧,SimpleDateFormat
是宽容的,但却是一种错误的方式。
答案 1 :(得分:0)
这没有意义。这对我来说听起来像个错误。
我认为正确的答案是等待最终完成日期的Java 8。例如,您的代码现在可以更改为类似下面的内容。并且,Java会抛出异常,就像它应该的那样。
import java.util.*;
import java.lang.*;
import java.io.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
String dubiousDate = "2014-04-01";
LocalDate d;
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
d = LocalDate.parse(dubiousDate, formatter);
System.out.println(dubiousDate + " -> " + d);
}
catch (Exception e) {
e.printStackTrace();
System.err.println(dubiousDate + " failed");
}
}
}
}