How to sanity check a date in Java How to sanity check a date in Java java java

How to sanity check a date in Java


Key is df.setLenient(false);. This is more than enough for simple cases. If you are looking for a more robust (I doubt) and/or alternate libraries like joda-time then look at the answer by the user "tardate"

final static String DATE_FORMAT = "dd-MM-yyyy";public static boolean isDateValid(String date) {        try {            DateFormat df = new SimpleDateFormat(DATE_FORMAT);            df.setLenient(false);            df.parse(date);            return true;        } catch (ParseException e) {            return false;        }}


As shown by @Maglob, the basic approach is to test the conversion from string to date using SimpleDateFormat.parse. That will catch invalid day/month combinations like 2008-02-31.

However, in practice that is rarely enough since SimpleDateFormat.parse is exceedingly liberal. There are two behaviours you might be concerned with:

Invalid characters in the date stringSurprisingly, 2008-02-2x will "pass" as a valid date with locale format = "yyyy-MM-dd" for example. Even when isLenient==false.

Years: 2, 3 or 4 digits?You may also want to enforce 4-digit years rather than allowing the default SimpleDateFormat behaviour (which will interpret "12-02-31" differently depending on whether your format was "yyyy-MM-dd" or "yy-MM-dd")

A Strict Solution with the Standard Library

So a complete string to date test could look like this: a combination of regex match, and then a forced date conversion. The trick with the regex is to make it locale-friendly.

  Date parseDate(String maybeDate, String format, boolean lenient) {    Date date = null;    // test date string matches format structure using regex    // - weed out illegal characters and enforce 4-digit year    // - create the regex based on the local format string    String reFormat = Pattern.compile("d+|M+").matcher(Matcher.quoteReplacement(format)).replaceAll("\\\\d{1,2}");    reFormat = Pattern.compile("y+").matcher(reFormat).replaceAll("\\\\d{4}");    if ( Pattern.compile(reFormat).matcher(maybeDate).matches() ) {      // date string matches format structure,       // - now test it can be converted to a valid date      SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance();      sdf.applyPattern(format);      sdf.setLenient(lenient);      try { date = sdf.parse(maybeDate); } catch (ParseException e) { }    }     return date;  }   // used like this:  Date date = parseDate( "21/5/2009", "d/M/yyyy", false);

Note that the regex assumes the format string contains only day, month, year, and separator characters. Aside from that, format can be in any locale format: "d/MM/yy", "yyyy-MM-dd", and so on. The format string for the current locale could be obtained like this:

Locale locale = Locale.getDefault();SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale );String format = sdf.toPattern();

Joda Time - Better Alternative?

I've been hearing about joda time recently and thought I'd compare. Two points:

  1. Seems better at being strict about invalid characters in the date string, unlike SimpleDateFormat
  2. Can't see a way to enforce 4-digit years with it yet (but I guess you could create your own DateTimeFormatter for this purpose)

It's quite simple to use:

import org.joda.time.format.*;import org.joda.time.DateTime;org.joda.time.DateTime parseDate(String maybeDate, String format) {  org.joda.time.DateTime date = null;  try {    DateTimeFormatter fmt = DateTimeFormat.forPattern(format);    date =  fmt.parseDateTime(maybeDate);  } catch (Exception e) { }  return date;}


You can use SimpleDateFormat

For example something like:

boolean isLegalDate(String s) {    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");    sdf.setLenient(false);    return sdf.parse(s, new ParsePosition(0)) != null;}