Java:日付の文字列は有効?無効?

こんにちは、さるまりんです。

日付の文字列が有効か否かをチェックする方法です。

文字列をDateオブジェクトに変換

文字列を受け取ってそれがDateオブジェクトに変換できたら有効、そうでなければ無効で考えてみました。

public boolean isValidDate(String str) {
	// 日付文字列の形式はyyyy/MM/dd
	DateFormat df = new SimpleDateFormat("yyyy/MM/dd");
	Date dt;
	try {
		// 文字列strをDateに変換
		dt = df.parse(str);
	} catch (ParseException e) {
		// 変換できなければ無効
		return false;
	}
	// 変換できれば有効
	return true;
}

次のように試してみます。

dateStr = "2019/05/31"; // 有効
if(isValidDate(dateStr)) {
	System.out.println(dateStr + " 有効");
} else {
	System.out.println(dateStr + " 無効");
}

dateStr = "2019/06/31"; // 無効
if(isValidDate(dateStr)) {
	System.out.println(dateStr + " 有効");
} else {
	System.out.println(dateStr + " 無効");
}

実行すると次のように表示されます。

2019/05/31 有効
2019/06/31 有効

ん?あれ?6月31日が有効だと?

そうなんです。上の方法では有効か否かのチェックには不十分なんです。

できたDateオブジェクトはどうなってるの?

ParseExceptionが発生せずに進んだのですからDateオブジェクトができているはずです。

ではそれはどうなってるのかSystem.out.println(df.format(dt));でチェックしてみました。

中身の日付は

2019/07/01

でした。

なるほどです。6月の31日は7月の1日。溢れた分を無理やり?存在する日に変換してくれています。これでは6月31日が有効になってしまいます。

日付の文字列が有効か否かをチェックする方法

改良します。上の方法で不十分なので、変換されたDateを文字列に戻して、変換前と比較して同じなら有効としたらいいですね。

改良版のメソッドは次の通りです。

public boolean isValidDate(String str) {
	// 日時の文字列の形式はyyyy/MM/dd
	DateFormat df = new SimpleDateFormat("yyyy/MM/dd");
	Date dt;
	try {
		// 文字列strをDateに変換
		dt = df.parse(str);
	} catch (ParseException e) {
		// 変換できなければfalse
		return false;
	}
	// 文字列に戻す
	String dateString = df.format(dt);
	// 元の文字列と戻した文字列が一致すればtrue
	return dateString.equals(str);
}

同じように試してみます。

2019/05/31 有効
2019/06/31 無効

成功です!

うまく動作してくれるようになりました。

これは気をつけないとハマりますね〜。注意が必要ですね。

思い込みだけでは危険です。テストって大切ですね。

読んでくださってありがとうございます。

ではまた!