2013-03-11 128 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 ,您可以。

相關問題