39

文字列形式の日付があり、それをutildateに解析したいと思います。

var date ="03/11/2013"

私はこれを次のように解析しています:

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

しかし、奇妙なことに、「03-08-201309hjhkjhk」または「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
4

2 に答える 2

73

使用する必要がありますDateFormat.setLenient(false)

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

それがあなたが望むすべてを捕らえるかどうかはsetLenient(false)わかりません-あなたが予想するよりも寛大であっても-それは例えば無効な月の数字を捕らえるはずです。

「2013年3月1日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です。

于 2013-03-11T10:33:02.677 に答える
11

Jon Skeetの答えは正解であり、2013年に書かれたときは良い答えでした。

ただし、質問で使用するクラスSimpleDateFormatDate現在古くなっているため、今日誰かが同様の問題を抱えている場合、IMHOの最善の答えは、最新のJava date& timeAPIを使用するように変更することです。

申し訳ありませんが、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"ます。かなり正確ですね。ただし、最新のAPIには、文字列の一部のみを解析するメソッドがあります。DateTimeParseExceptionText '03/88/2013 hjhkjhk' could not be parsed, unparsed text found at index 10
  • "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-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);

これで、も解析"03/88/2013"されて。になり2013-05-27ます。これは古いクラスでも行われていたことだと思います。3月の初めから88日を数えると、5月27日になります。他のエラーメッセージは同じです。言い換えれば、それはまだ解析されていないテキスト、6桁の年、およびハイフンに反対します。

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

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

  • Java 8以降では、新しいAPIが組み込まれています。
  • Java 6および7では、新しいクラスのバックポートであるThreeTenバックポートを取得します(これは、最新のAPIが最初に定義されたJSR-310のThreeTenです)。
  • Androidでは、Android版のThreeTenBackportを使用します。これはThreeTenABPと呼ばれ、この質問にはすばらしい説明があると思います。AndroidプロジェクトでThreeTenABPを使用する方法です。
于 2017-07-27T09:37:42.153 に答える