こんな感じのプログラムを作った。
日付の範囲を指定して、データベースからデータを取得するような処理だ。
入力情報である日付Fromと日付ToはdateCheckメソッドにてチェックされ、不正な日付の場合は代わりの日付が指定される仕組みだ。
/** データ取得処理 */
public List<Object> select(Connection conn, String dateFrom, String dateTo) {
List<Object> result = new ArrayList<Object>();
dateFrom = dateCheck(dateFrom, "2000/01/01");
dateTo = dateCheck(dateTo, "2020/12/31");
String sql = "SELECT * FROM TARGET_TABLE "
+ " WHERE ENTRY_DATE BETWEEN TO_DATE(?, 'yyyy/mm/dd') AND TO_DATE(?, 'yyyy/mm/dd')";
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
ps.setString(1, dateFrom);
ps.setString(2, dateFrom);
rs = ps.executeQuery();
// データ取得&リスト格納処理
// ...
} catch (SQLException e) {
} finally {
// クローズ処理
}
return result;
}
/** 日付チェック */
private String dateCheck(String dateString, String alternativeDateString) {
String result = "";
DateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
sdf.setLenient(false);
try {
sdf.parse(dateString);
result = dateString;
} catch (ParseException e) {
result = alternativeDateString;
}
return result;
}
どこが問題かというと、「20001/1/1」みたいな、西暦年が5桁の日付を与えてみたところ、dateCheckをクリアしてしまった、というところだ。
どうやらSimpleDateFormatは西暦年が5桁でもしれっと処理してしまうらしい。
こんなプログラムも書いてみたが↓
public static void main(String[] args) throws ParseException {
String s = "20001/1/1";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
sdf.setLenient(false);
Date d = sdf.parse(s);
System.out.println(d);
}
コンソールには「Mon Jan 01 00:00:00 JST 20001」と表示された。
で、これだけならいいのだが、データベース(発見時はOracleを使用)が西暦年5桁は受け入れてくれなかったりする。すなわち、最初に例示した類のプログラムを実行すると
java.sql.SQLException: ORA-01861: リテラルが書式文字列と一致しません
になってしまう。
解決するためには、正規表現によるチェックか文字列の長さチェックでSimpleDateFormat#parseの穴を補うしかないかもしれない。また、値が画面から入力される類のものであるならば、その画面に入力制限をつけて不正な日付を入力させない、などの処置が必要になると思う。