Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>As shown by @Maglob, the basic approach is to test the conversion from string to date using <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/text/SimpleDateFormat.html" rel="noreferrer">SimpleDateFormat.parse</a>. That will catch invalid day/month combinations like 2008-02-31.</p> <p>However, in practice that is rarely enough since SimpleDateFormat.parse is exceedingly liberal. There are two behaviours you might be concerned with:</p> <p><strong>Invalid characters in the date string</strong> Surprisingly, 2008-02-2x will "pass" as a valid date with locale format = "yyyy-MM-dd" for example. Even when isLenient==false.</p> <p><strong>Years: 2, 3 or 4 digits?</strong> 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")</p> <h2>A Strict Solution with the Standard Library</h2> <p>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.</p> <pre><code> 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); </code></pre> <p>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:</p> <pre><code>Locale locale = Locale.getDefault(); SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale ); String format = sdf.toPattern(); </code></pre> <h2>Joda Time - Better Alternative?</h2> <p>I've been hearing about <a href="http://joda-time.sourceforge.net/" rel="noreferrer">joda time</a> recently and thought I'd compare. Two points:</p> <ol> <li>Seems better at being strict about invalid characters in the date string, unlike SimpleDateFormat</li> <li>Can't see a way to enforce 4-digit years with it yet (but I guess you could create your own <a href="http://joda-time.sourceforge.net/api-release/org/joda/time/format/DateTimeFormatter.html" rel="noreferrer">DateTimeFormatter</a> for this purpose)</li> </ol> <p>It's quite simple to use:</p> <pre><code>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; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload