java.text.SimpleDateFormat 中的奇怪行为期望 yyyyMMdd 给定 yyyy-MM-dd
我在使用 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”
初始化但要解析的字符串格式为“yyyy-MM-dd”
。我希望这样的事情会导致 ParseException
,或者至少在尽力而为的基础上正确进行解析。相反,由于某种奇怪的原因,日期被解析为 2011-11-02
。诶?!
这是不可接受的,因为处理输入时的一个错误就会导致完全意外/毁灭性的结果。同时切换到 JodaTime,但很高兴了解那里出了什么问题。
I have encountered a very weird behavior while using SimpleDateFormat
for parsing a string to a date. Consider the following unit test:
@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));
}
As it can be seen there is an intentional mistake in the above code: the SimpleDateFormat
is initialized with "yyyyMMdd"
but the string to be parsed is in the format "yyyy-MM-dd"
. I would expect that such thing results in a ParseException
, or at least be parsed on a best-effort basis correctly. Instead, for some weird reason the date is parsed as 2011-11-02
. Eh?!
This is unacceptable as one single mistake while handling the inputs would result in something totally unexpected / devastating. Switched to JodaTime in the meantime, but it would be nice to understand what went wrong there.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
摘自 JavaDoc for
setLenient
:如果将其设置为 false,您将得到
ParseException
Extract from JavaDoc for
setLenient
:If you set it to false, you will get
ParseException
如果使用
DateFormat.parse()
函数,字符串必须满足输入格式。如果不这样做,则解析函数解析错误。 javaDoc 中有对此的评论:然后,添加
setLenient(false)
行即可解决您的问题。在这种情况下,Java 会抛出异常。If you use the
DateFormat.parse()
function, the string must satisfy the input format. if it doesn't do it, the parse function parse wrong. Here a comment about this in the javaDoc:Then, your problem would be fixed adding the
setLenient(false)
line. In this case, Java throws the exception.那么,输入将分为 3 个部分:年、月、日,您将得到
month = -12和day = -21(更正请参见下文) 。尝试解析2012/12/21
,你会得到异常:)编辑:摘自JavaDoc:
Edit2:更正
查看
SimpleDateFormat
的源代码,似乎2012-12-21
实际上分为:源代码注释指出
-
> 后面的数字可能表示负数(取决于区域设置)或分隔符。在您的情况下,它似乎被视为分隔符,因此day = "2-"
结果为day = 2
,因此 second十一月。Well, the input would be split into 3 components: year, month, day and you'd get
month = -12andday = -21(for correction see below). Try to parse2012/12/21
and you'll get the exception :)Edit: excerpt from the JavaDoc:
Edit2: Correction
Looking at the source of
SimpleDateFormat
it seems that2012-12-21
is actually split into this:The source comments state that a
-
following a number might either denote a negative number (depending on the locale) or be a delimiter. In your case it seems to be taken as a delimiter, thusday = "2-"
results inday = 2
, hence the second of November.您需要调用 setLenient(false)。默认值为 true,Java 会尝试转换字符串,即使它不匹配 100%。
You need to call setLenient(false). The default is true and Java tries to convert the string even it does not match 100%.