给出yyyy-MM-dd的java.text.SimpleDateFormat期待yyyyMMdd的奇怪行为

时间:2011-07-28 12:48:21

标签: java simpledateformat

使用SimpleDateFormat将字符串解析为日期时,我遇到了一种非常奇怪的行为。考虑以下单元测试:

@Test
public void testParse() throws ParseException
{
    DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");

    String dateStr = "2012-12-21";
    Date parsedDate = dateFormat.parse(dateStr);
    Calendar date = Calendar.getInstance();
    date.setTime(parsedDate);

    Assert.assertEquals(2012, date.get(Calendar.YEAR));
    Assert.assertEquals(11, date.get(Calendar.MONTH)); // yeah, Calendar sucks
    Assert.assertEquals(21, date.get(Calendar.DAY_OF_MONTH));
}

可以看出上面的代码中有一个故意的错误SimpleDateFormat初始化为"yyyyMMdd",但要解析的字符串格式为{ {1}}。我希望这样的事情导致"yyyy-MM-dd",或者至少在尽力而为的基础上正确解析。相反,由于一些奇怪的原因,日期被解析为ParseException。嗯?!

这是不可接受的,因为处理输入时的一个错误会导致完全意外/毁灭性的事情。在此期间切换到JodaTime,但是理解那里出了什么问题会很好。

4 个答案:

答案 0 :(得分:12)

摘自JavaDoc for setLenient

  

public void setLenient(boolean lenient)

     

指定日期/时间解析是否宽松。通过宽松的解析,解析器可以使用启发式来解释与该对象的格式不完全匹配的输入。
  通过严格的解析,输入必须与此对象的格式匹配。

如果您将其设置为false,则会获得ParseException

答案 1 :(得分:4)

如果使用DateFormat.parse()函数,则字符串必须满足输入格式。如果不这样做,解析函数解析错误。这里有关于javaDoc的评论:

  

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

然后,添加setLenient(false)行将解决您的问题。在这种情况下,Java会抛出异常。

答案 2 :(得分:2)

那么,输入将分为3个组成部分:年,月,日,你得到 month = -12 day = -21 (用于更正)见下文)。尝试解析2012/12/21,你会得到例外:)

编辑:摘自JavaDoc:

  

月份:如果模式字母的数量为3或更多,则将月份解释为文本;否则,它被解释为数字。

Edit2:更正

查看SimpleDateFormat的来源,似乎2012-12-21实际上已分为:

year = "2012"
month = "-1"
day = "2-" 

源注释表明数字后面的-可能表示负数(取决于区域设置)或是分隔符。在你的情况下,它似乎被视为分隔符,因此day = "2-"导致day = 2,因此11月的

答案 3 :(得分:1)

您需要调用setLenient(false)。默认值为true,Java尝试转换字符串,即使它与100%不匹配。