简体   繁体   English

为什么 SimpleDateFormat 解析不正确的日期?

[英]Why does SimpleDateFormat parse incorrect date?

I have date in string format and I want to parse that into util date.我有字符串格式的日期,我想将其解析为实用日期。

var date ="03/11/2013"

I am parsing this as:我将其解析为:

new SimpleDateFormat("MM/dd/yyyy").parse(date)

But the strange thing is that, if I am passing "03-08- 201309 hjhkjhk " or "03- 88 -2013" or 43 -88-201378", it does not throw error, it parses it.但奇怪的是,如果我传递“03-08-201309 hjhkjhk ”或“ 03-88 -2013”或43 -88-201378”,它不会抛出错误,它会解析它。

For this now, I have to write regex pattern for checking whetehr input of date is correct or not.为此,我必须编写正则表达式模式来检查日期的输入是否正确。 but why is it so??但为什么会这样??

Code:代码:

scala> val date="03/88/201309 hjhkjhk"
date: java.lang.String = 03/88/201309 hjhkjhk

scala> new SimpleDateFormat("MM/dd/yyyy").parse(date)
res5: java.util.Date = Mon May 27 00:00:00 IST 201309

You should use DateFormat.setLenient(false) : 您应该使用DateFormat.setLenient(false)

SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
df.setLenient(false);
df.parse("03/88/2013"); // Throws an exception

I'm not sure that will catch everything you want - I seem to remember that even with setLenient(false) it's more lenient than you might expect - but it should catch invalid month numbers for example. 我不确定它会捕获你想要的一切 - 我似乎记得即使使用setLenient(false)它比你预期的更宽松 - 但它应该捕获无效的月份数例如。

I don't think it will catch trailing text, eg "03/01/2013 sjsjsj". 我认为它不会捕获尾随文本,例如“03/01/2013 sjsjsj”。 You could potentially use the overload of parse which accepts a ParsePosition , then check the current parse index after parsing has completed: 您可能会使用接受ParsePositionparse重载,然后在解析完成后检查当前的解析索引:

ParsePosition position = new ParsePosition(0);
Date date = dateFormat.parse(text, position);
if (position.getIndex() != text.length()) {
    // Throw an exception or whatever else you want to do
}

You should also look at the Joda Time API which may well allow for a stricter interpretation - and is a generally cleaner date/time API anyway. 您还应该查看Joda Time API,这可能会允许更严格的解释 - 并且无论如何都是一个通常更干净的日期/时间API。

Jon Skeet's answer is correct and was a good answer when it was written in 2013. Jon Skeet的回答是正确的,并且在2013年撰写时是一个很好的答案。

However, the classes you use in your question, SimpleDateFormat and Date , are now long outdated, so if someone got a similar issue with them today, IMHO the best answer would be to change to using the modern Java date & time API . 但是,您在问题中使用的类, SimpleDateFormatDate ,现在已经过时了,所以如果有人今天遇到类似的问题,恕我直言,最好的答案是改为使用现代Java日期和时间API

I am sorry I cannot write Scala code, so you will have to live with Java. 很抱歉,我无法编写Scala代码,因此您将不得不使用Java。 I am using 我在用

private static DateTimeFormatter parseFormatter
        = DateTimeFormatter.ofPattern("MM/dd/yyyy");

The format pattern letters are the same as in your question, though the meaning is slightly different. 格式模式字母与您的问题中的相同,但含义略有不同。 DateTimeFormatter takes the number of pattern letters literally, as we shall see. 正如我们将要看到的, DateTimeFormatter获取模式字母的数量。 Now we try: 现在我们尝试:

        System.out.println(LocalDate.parse(date, parseFormatter));

Results: 结果:

  • "03/11/2013" is parsed into 2013-03-11 as expected. "03/11/2013"按预期解析为2013-03-11 I used the modern LocalDate class, a class that represents a date without time-of-day, exactly what we need here. 我使用了现代的LocalDate类,这是一个代表没有时间的日期的类,正是我们在这里需要的。
  • Passing "03/88/2013 hjhkjhk" gives a DateTimeParseException with the message Text '03/88/2013 hjhkjhk' could not be parsed, unparsed text found at index 10 . 传递"03/88/2013 hjhkjhk"给出一个DateTimeParseException ,消息Text '03/88/2013 hjhkjhk' could not be parsed, unparsed text found at index 10 Pretty precise, isn't it? 很精确,不是吗? The modern API has methods to parse only part of a string if that is what we want, though. 如果这是我们想要的,那么现代API具有仅解析字符串的一部分的方法。
  • "03/88/201309" gives Text '03/88/201309' could not be parsed at index 6 . "03/88/201309"给出Text '03/88/201309' could not be parsed at index 6 We asked for a 4 digit year and gave it 6 digits, which leads to the objection. 我们要求一个4位数的年份并给它6位数,这导致了反对意见。 Apparently it detects and reports this error before trying to interpret 88 as a day of month. 显然,在尝试将88解释为月中的某一天之前,它会检测并报告此错误。
  • It does object to a day of month of 88 too, though: "03/88/2013" gives Text '03/88/2013' could not be parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 88 . 它确实反对88的月份,但是: "03/88/2013" Text '03/88/2013' could not be parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 88 "03/88/2013" Text '03/88/2013' could not be parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 88 Again, please enjoy how informative the message is. 再次,请享受信息的信息。
  • "03-08-2013" (with hyphens instead of slashes) gives Text '03-08-2013' could not be parsed at index 2 , not very surprising. "03-08-2013" (用连字符而不是斜线)使得Text '03-08-2013' could not be parsed at index 2 ,这并不令人惊讶。 Index 2 is where the first hyphen is. 索引2是第一个连字符的位置。

Jon Skeet explained that the outdated SimpleDateFormat can be lenient or non-lenient. Jon Skeet解释说,过时的SimpleDateFormat可以是宽松的或非宽松的。 This is true for DateTimeFormatter too, in fact it has 3 instead of 2 resolver styles, called 'lenient', 'smart' and 'strict'. 对于DateTimeFormatter也是如此,事实上它有3个而不是2个解析器样式,称为'lenient','smart'和'strict'。 Since many programmers are not aware of this, though, I think they made a good choice of not making 'lenient' the default ('smart' is). 但是,由于许多程序员都没有意识到这一点,我认为他们做出了一个很好的选择,就是不要将'lenient'作为默认值('smart')。

What if we wanted to make our formatter lenient? 如果我们想让格式化程序宽松怎么办?

private static DateTimeFormatter parseFormatter
        = DateTimeFormatter.ofPattern("MM/dd/yyyy")
                .withResolverStyle(ResolverStyle.LENIENT);

Now it also parses "03/88/2013" , into 2013-05-27 . 现在它还解析"03/88/2013" ,进入2013-05-27 I believe this is what the old class would also have done: counting 88 days from the beginning of March gives May 27. The other error messages are still the same. 我相信这就是旧班级也会做的事情:从3月初算起88天到5月27日。其他错误信息仍然是相同的。 In other words it still objects to unparsed text, to a 6 digit year and to hyphens. 换句话说,它仍然反对未解析的文本,6位数年份和连字符。

Question: Can I use the modern API with my Java version? 问题:我可以在Java版本中使用现代API吗?

If using at least Java 6 , you can. 如果至少使用Java 6 ,则可以。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM