2013-03-11 93 views
27

我有字符串格式的日期,我想解析到util日期。为什么SimpleDateFormat解析不正确的日期?

var date ="03/11/2013" 

我解析此为:

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

但奇怪的是,如果我传递 “03-08- 201309 hjhkjhk” 或“03- -2013 “或 -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 
+3

'var date'?我不这么认为,请将您的真实代码复制到问题中。 – Perception 2013-03-11 10:26:35

+0

'var date'不是Java。 – 2013-03-11 10:26:42

+1

@Lutz Horn。我正在使用scala – Rishi 2013-03-11 10:51:37

回答

48

你应该使用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”。你可能使用的parse它接受一个ParsePosition超载,然后检查当前的分析指标分析完成后:

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。

+1

df.parse(“03/08/2013xskhs”); 这里没有错误。 – Rishi 2013-03-11 10:39:17

+0

@Rishi:是的,我正在编辑我的答案,以包含该部分以及其他建议。 (我现在编辑它进一步。) – 2013-03-11 10:40:12

+0

如果您想要捕捉尾随文本,那么您需要使用parse(String text,ParsePosition pos)版本的解析方法,因为您可以检查是否所有输入都被消耗。 – 2013-03-11 10:42:48

3

Jon Skeet’s answer是正确的,是当它被写在2013年

但是一个很好的答案,你在你的问题,SimpleDateFormatDate使用类,现在早已过时,因此,如果有人得到了类似的问题与他们今天,恕我直言,最好的答案是改为使用the modern Java date & time 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解释为一个月中的某一天之前检测并报告此错误。
  • 虽然:"03/88/2013"给出了Text '03/88/2013' could not be parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 88,但它反对到88的月份。再次,请欣赏信息的信息量。
  • "03-08-2013"(用连字符代替斜线)给出Text '03-08-2013' could not be parsed at index 2,这并不令人惊讶。索引2是第一个连字符的位置。

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

如果我们想让我们的格式化程序变得宽容呢?

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 ,您可以。

相关问题