SimpleDateFormat电话号码意外成功

时间:2013-10-22 14:55:46

标签: java string datetime

无意中将电话号码字符串传入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;
}

3 个答案:

答案 0 :(得分:7)

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

promsiedDateTimeFormat.setLenient(false);

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

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

答案 1 :(得分:3)

来自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)

来坚持严格遵守格式

所以,只需将宽容设置为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的帖子