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

Dan*_*yes 9 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));
}
Run Code Online (Sandbox Code Playgroud)

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

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

Ser*_*nov 12

JavaDoc中setLenient提取:

public void setLenient(boolean lenient)

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

如果你把它设置为假,你就会得到 ParseException


Tho*_*mas 2

那么,输入将分为 3 个部分:年、月、日,您将得到月 = -12日 = -21(更正请参见下文)。尝试解析2012/12/21,你会得到异常:)

编辑:摘自JavaDoc:

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

编辑2:更正

看看SimpleDateFormat它的来源似乎2012-12-21实际上分为这样的:

year = "2012"
month = "-1"
day = "2-" 
Run Code Online (Sandbox Code Playgroud)

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