繁体   English   中英

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

[英]Why does SimpleDateFormat parse incorrect date?

我有字符串格式的日期,我想将其解析为实用日期。

var date ="03/11/2013"

我将其解析为:

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

但奇怪的是,如果我传递“03-08-201309 hjhkjhk ”或“ 03-88 -2013”或43 -88-201378”,它不会抛出错误,它会解析它。

为此,我必须编写正则表达式模式来检查日期的输入是否正确。 但为什么会这样??

代码:

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

您应该使用DateFormat.setLenient(false)

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

我不确定它会捕获你想要的一切 - 我似乎记得即使使用setLenient(false)它比你预期的更宽松 - 但它应该捕获无效的月份数例如。

我认为它不会捕获尾随文本,例如“03/01/2013 sjsjsj”。 您可能会使用接受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
}

您还应该查看Joda Time API,这可能会允许更严格的解释 - 并且无论如何都是一个通常更干净的日期/时间API。

Jon Skeet的回答是正确的,并且在2013年撰写时是一个很好的答案。

但是,您在问题中使用的类, SimpleDateFormatDate ,现在已经过时了,所以如果有人今天遇到类似的问题,恕我直言,最好的答案是改为使用现代Java日期和时间API

很抱歉,我无法编写Scala代码,因此您将不得不使用Java。 我在用

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

格式模式字母与您的问题中的相同,但含义略有不同。 正如我们将要看到的, DateTimeFormatter获取模式字母的数量。 现在我们尝试:

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

结果:

  • "03/11/2013"按预期解析为2013-03-11 我使用了现代的LocalDate类,这是一个代表没有时间的日期的类,正是我们在这里需要的。
  • 传递"03/88/2013 hjhkjhk"给出一个DateTimeParseException ,消息Text '03/88/2013 hjhkjhk' could not be parsed, unparsed text found at index 10 很精确,不是吗? 如果这是我们想要的,那么现代API具有仅解析字符串的一部分的方法。
  • "03/88/201309"给出Text '03/88/201309' could not be parsed at index 6 我们要求一个4位数的年份并给它6位数,这导致了反对意见。 显然,在尝试将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 再次,请享受信息的信息。
  • "03-08-2013" (用连字符而不是斜线)使得Text '03-08-2013' could not be parsed at index 2 ,这并不令人惊讶。 索引2是第一个连字符的位置。

Jon Skeet解释说,过时的SimpleDateFormat可以是宽松的或非宽松的。 对于DateTimeFormatter也是如此,事实上它有3个而不是2个解析器样式,称为'lenient','smart'和'strict'。 但是,由于许多程序员都没有意识到这一点,我认为他们做出了一个很好的选择,就是不要将'lenient'作为默认值('smart')。

如果我们想让格式化程序宽松怎么办?

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

现在它还解析"03/88/2013" ,进入2013-05-27 我相信这就是旧班级也会做的事情:从3月初算起88天到5月27日。其他错误信息仍然是相同的。 换句话说,它仍然反对未解析的文本,6位数年份和连字符。

问题:我可以在Java版本中使用现代API吗?

如果至少使用Java 6 ,则可以。

暂无
暂无

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

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