3

意外地将电话号码字符串传递到SimpleDateFormat的格式方法中有时会导致解析有效日期。

例如,传递数字“518-123-4567”(文字,带连字符)会以某种方式导致日期为“11/23/0517 05:27 AM”

我们在一个字符串可以代表许多不同事物的领域中使用它,并且我们假设一个带有数字和连字符的字符串在被解析为日期时会失败。我们的代码只是简单地检查 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;
}
4

3 回答 3

7

SimpleDateFormat处于“宽松”模式 - 这确实非常宽松。如果你使用

promsiedDateTimeFormat.setLenient(false);

当您尝试解析虚假数据时,它会抛出您所期望的异常。

我个人认为默认情况下应该是严格的,但是......

于 2013-10-22T15:01:03.907 回答
2

来自DateFormat#parse(String)

从给定字符串的开头解析文本以生成日期。该方法可能不会使用给定字符串的整个文本。

因此,该方法可能不会解析整个字符串。它将停在模式停止匹配的位置。在您的情况下,匹配是通过以下方式完成的:

yyyy  MM   dd  HH   mm
518   -1   23  -4   567

年份解析yyyy首先停止-,因为它不能解析为年份。所以,年份是518。然后将月份作为-1,然后23作为dd,依此类推。

您可以使用parse方法的重载版本并传递一个ParsePosition实例来查看详细信息。

来自DateFormat#parse(String, ParsePosition)

默认情况下,解析是宽松的:如果输入不是该对象的格式方法使用的格式,但仍然可以解析为日期,则解析成功。客户可以通过调用 setLenient(false) 来坚持严格遵守格式

因此,只需将 leniency 设置为false, 以阻止它解析与格式不匹配的日期:

promsiedDateTimeFormat.setLenient(false);

例如,在 usingParsePosition时,假设您将日期字符串作为 - 传递"518-123-4567abc"。令人惊讶的是,它也会被解析为 leniency 设置为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;
}
于 2013-10-22T15:11:18.487 回答
1

解释发生了什么:581 年,-1 月,23 日,-4 小时,567 分钟。将所有内容相加,您将得到结果日期。要获得这样的结果,请参阅 JonSkeet 的帖子

于 2013-10-22T15:03:55.027 回答