2013-03-11 15 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

+0

'var date'はJavaではありません。 –

+1

@Lutzホーン。私はscalaを使用しています – Rishi

答えて

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"解析が完了した後にあなたが潜在的にParsePositionを受け入れparseのオーバーロードを使用することができ、その後、現在の解析指標をチェックしてください。

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

+0

@Rishi:はい、私はその部分を他の提案と一緒に含めるように答えを編集していました。 (私はこれをさらに編集しました) –

+0

末尾のテキストを捕捉したい場合は、parseメソッドの 'parse(String text、ParsePosition pos)'バージョンを使用し、すべての入力が消費されたかどうかを確認する必要があります。 –

3

Jon Skeet’s answerは正しく、それはしかし、2013年

で書かれた良い答えだった、誰かがで同様の問題を得たので、もし、あなたの質問、SimpleDateFormatDateに使用するクラスは、今長い時代遅れですそれらの今日、IMHO最も良い答えは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"を渡すと、メッセージText '03/88/2013 hjhkjhk' could not be parsed, unparsed text found at index 10DateTimeParseExceptionが得られます。かなり正確ですね。現代のAPIには、文字列の一部のみを解析するメソッドがあります。
  • "03/88/201309"は、Text '03/88/201309' could not be parsed at index 6となる。私たちは4桁の年を求め、それに6桁を与えました。これが反対につながります。明らかに、このエラーを検出して報告してから、88日を月として解釈しようとしています。
  • でも、8831の月の日には反対ですが、"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でも当てはまりますが、実際には 'lenient'、 'smart'、 'strict'という2つのリゾルバスタイルの代わりに3つのスタイルがあります。しかし、多くのプログラマーがこれを認識していないので、彼らはデフォルトの「寛大な」(スマートな)ものではないという良い選択をしたと思います。

フォーマッタを寛容にしたいのですが?

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

今も2013-05-27に、"03/88/2013"を解析します。私はこれが古いクラスもやったと思う:3月初めから88日を計算すると5月27日になる。他のエラーメッセージはまだ同じである。つまり、解析されていないテキスト、6桁の年、ハイフンには依然として反対します。

質問:私のJavaバージョンで最新のAPIを使用できますか?

少なくともJava を使用している場合は、可能です。

  • Java 8以降では、新しいAPIが組み込まれています。
  • Java 6および7では、新しいクラスのバックポート(最新のAPIが最初に定義されたJSR-310のThreeTenです)を取得します(the ThreeTen Backport)。
  • Androidでは、Android版のThreeTen Backportを使用してください。それはThreeTenABPと呼ばれ、this question: How to use ThreeTenABP in Android Projectに素晴らしい説明があると思います。
関連する問題