无意中将电话号码字符串传入SimpleDateFormat的格式方法,有时会导致有效日期被解析。
作为一个例子,传递数字“518-123-4567”(字面,带连字符)不知何故导致日期“11/23/0517 05:27 AM”
我们在一个String可以表示许多不同内容的区域中使用它,并且我们假设一个字符串,其中包含数字和连字符,通常是电话号码的方式在解析为日期时,写入会失败。我们的代码只是检查ParseException,并接受任何不会抛出此类异常的内容。 为什么这种字符串无法解析?有没有更好的方法来检查字符串是否可能成为日期?
private static Date getPromisedDate(String promisedText) {
SimpleDateFormat promsiedDateTimeFormat = new SimpleDateFormat("yyyyMMddHHmm");
if(null != promisedText) {
try {
return promsiedDateTimeFormat.parse(promisedText);
}
catch (ParseException e) { }
}
return null;
}
答案 0 :(得分:7)
你的SimpleDateFormat
处于“宽松”模式 - 这确实非常宽松。如果你使用
promsiedDateTimeFormat.setLenient(false);
当您尝试解析虚假数据时,它会抛出异常。
我个人认为默认情况下它应该是严格的,但是......
答案 1 :(得分:3)
从给定字符串的开头解析文本以生成日期。该方法可能不会使用给定字符串的整个文本。
因此,该方法可能无法解析整个字符串。它将停在模式停止匹配的位置。在您的情况下,匹配是以这些方式完成的:
yyyy MM dd HH mm
518 -1 23 -4 567
解析yyyy
的年份在第一个-
停止,因为它无法解析为年份。所以,这一年是518
。然后将月份视为-1
,然后将23
视为dd
,依此类推。
您可以使用parse
方法的重载版本并传递ParsePosition
实例以查看详细信息。
来自DateFormat#parse(String, ParsePosition)
:
默认情况下,解析是宽松的:如果输入不是此对象的格式方法使用的形式,但仍可以解析为日期,则解析成功。客户可以通过调用setLenient(false)
来坚持严格遵守格式
所以,只需将宽容设置为false
,以阻止它解析与格式不匹配的日期:
promsiedDateTimeFormat.setLenient(false);
例如,在使用ParsePosition
时,假设您将日期字符串作为 - "518-123-4567abc"
传递。令人惊讶的是,它也会被解析为宽容设置为true
,因为根本不会解析最后一部分abc
。要对此进行测试,您可以尝试以下代码:
private static Date getPromisedDate(String promisedText) throws Exception {
ParsePosition pp = new ParsePosition(0);
SimpleDateFormat promsiedDateTimeFormat = new SimpleDateFormat("yyyyMMddHHmm");
if(null != promisedText) {
try {
Date date = promsiedDateTimeFormat.parse(promisedText);
// If complete string is not parsed, throw ParseException
if (pp.getIndex() != promisedText.length()) {
throw new ParseException("Unparseable date given: " + promisedText, pp.getIndex());
}
return date;
}
catch (ParseException e) { throw e; }
}
return null;
}
答案 2 :(得分:1)
解释发生了什么:年份581,第-1个月,第23天,第4小时,分钟567.总结一切,您将得到结果日期。要了解此类结果,请参阅JonSkeet的帖子