簡體   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