需求:由于系统有不少日期格式,因此日期验证函数的输入是一个日期字符串和一个格式字符串。格式字符串用的是Java定义的格式(参考地址)。正则表达式
刚开始写时,以为很简单,直接就写了下面的代码。函数
public static boolean isDate(String dttm, String format) { boolean retValue = false; if (dttm != null) { SimpleDateFormat formatter = new SimpleDateFormat(format); try { formatter.parse(dttm); retValue = true; } catch (ParseException e) { } } return retValue;
}测试
写好以后,一测试,发现2012/12/43这种日期竟然也返回True,因而查资料,设置转化时不进位formatter.setLenient(false);以后好用了,代码为code
public static boolean isDate(String dttm, String format) { boolean retValue = false; if (dttm != null) { SimpleDateFormat formatter = new SimpleDateFormat(format); formatter.setLenient(false); try { formatter.parse(dttm); retValue = true; } catch (ParseException e) { } } return retValue; }
写到这里,觉得万事大吉了。但以后的测试却发现,当日期有分隔符时,只会转换前一部分,好比2012/12/30ABCD也会返回True。想了一下,以为先转为日期型,再转为字符串,再比较二者是否相等,但立刻就否决了这个方案,由于客户要求的是不严格的日期形式,如格式为yyyy/MM/dd,输入2012/1/2也须要验证经过。而后考虑了一下,以为先用正则表达式作一次验证,而后再验证是不是日期型。代码以下orm
public static boolean isDate(String dttm, String format) { boolean retValue = false; if (dttm == null || dttm.isEmpty() || format == null || format.isEmpty()) { return retValue; } String regFormat = format; regFormat = regFormat.replaceAll("(^')|('$)", ""); regFormat = regFormat.replaceAll("'([^'])", "$1"); regFormat = regFormat.replace("''", "'"); regFormat = regFormat.replace("\\", "\\\\"); regFormat = regFormat.replaceAll("[MdHmsS]+", "\\d+"); regFormat = regFormat.replaceAll("[y]+", "\\d{1,4}"); if (!dttm.matches("^" + regFormat + "$")) { return false; } SimpleDateFormat formatter = new SimpleDateFormat(format); formatter.setLenient(false); try { formatter.parse(dttm); retValue = true; } catch (ParseException e) { } return retValue; }
上面的代码只对应了yMdHmsS,虽然对当时的系统已经足够了,但仍是感受不太爽,以为应该有一种通用的方法。因而查Java的API,发现parse方法还有一个带参数的方法。理解了它的使用方法以后,把代码改为下面的样子字符串
private static boolean isDate(String dttm, String format) { if (dttm == null || dttm.isEmpty() || format == null || format.isEmpty()) { return false; } DateFormat formatter = new SimpleDateFormat(format); formatter.setLenient(false); ParsePosition pos = new ParsePosition(0); Date date = formatter.parse(dttm, pos); if (date == null || pos.getErrorIndex() > 0) { return false; } if (pos.getIndex() != dttm.length()) { return false; } return true; }
原本觉得这样应该万事大吉了,但以后的测试又发现两个Bug。一个是,当输入的日期没有年份(需求是没有输入年份是默认当前年份)时,默认取的是1970年,这样的话,若是当年是闰年的话,2/29号就验证出错了;另外一个是Java的日期和Oracle的日期大小不一样,Oracle好像最大只支持到9999年,而Java能够有2万多年。因此代码又被改为了下面的样子get
private static boolean isDate(String dttm, String format) { if (dttm == null || dttm.isEmpty() || format == null || format.isEmpty()) { return false; } if (format.replaceAll("'.+?'", "").indexOf("y") < 0) { format += "/yyyy"; DateFormat formatter = new SimpleDateFormat("/yyyy"); dttm += formatter.format(new Date()); } DateFormat formatter = new SimpleDateFormat(format); formatter.setLenient(false); ParsePosition pos = new ParsePosition(0); Date date = formatter.parse(dttm, pos); if (date == null || pos.getErrorIndex() > 0) { return false; } if (pos.getIndex() != dttm.length()) { return false; } if (formatter.getCalendar().get(Calendar.YEAR) > 9999) { return false; } return true; }