Thursday, June 7th, 2007...10:47 am
Java Date Validation is Annoying (Regexes too)
*EDIT* Thanks for the tips in the comments.
Today I had a user complain that they could enter 2 digit years in their app. Hmm I took a look at the code and I didn't see how that was possible. Here was my date validation method, more after the jump.
{
if (str == null || str.equals(""))
{
return false;
}
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy");
sdf.setLenient(false); // force pattern to be enforced
java.sql.Date sqlDate;
try
{
sqlDate = new java.sql.Date(sdf.parse(str).getTime());
}
catch (ParseException e)
{
return false;
}
return true;
}
Hmm looks OK to me, the problem was that SimpleDateFormat doesn't work like I thought it would, turns out 01-01-20 will pass through the MM-dd-yyyy mask! So how do you enforce century matching with SimpleDateFormat? Who knows, I was too pissed off reading through the javadoc. Rather than waste time figuring it out I thought I'd just use a regular expression to make sure the string ends with 4 digits.
Wait that didn't work either. Now I'm really getting steamed, turns out not only do I not understand the SimpleDateFormat class, I also don't understand the matches method, turns out it doesn't do partial pattern matching.
So the correct pattern needs to match everything before the last 4 digits as well. So here's my final method.
public static boolean isDate(String str)
{
if (str == null || str.equals(""))
{
return false;
}
String p = ".*\\d\\d\\d\\d$";
if(!str.matches(p))
{
return false;
}
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy");
sdf.setLenient(false); // force pattern to be enforced
java.sql.Date sqlDate;
try
{
sqlDate = new java.sql.Date(sdf.parse(str).getTime());
}
catch (ParseException e)
{
return false;
}
return true;
}
Hooray, regex checks for a 4 digit year then simple date format does the leap year legwork and other shenanigans.
If someone who understands how the hell SimpleDateFormat works wants to enlighten me, by all means do so. This just goes to show you, don't make assumptions in Java, if you're not creating 74 objects and catching 812 exceptions then you're probably doing it wrong!







3 Comments
June 7th, 2007 at 3:44 pm
Or you could just use SimpleDateFormat("MM-dd-yy") to parse for both 2 and 4 digit years.
Example. This will always work in the first block.
String dateIn = "01-01-3020";
SimpleDateFormat sdf1 = new SimpleDateFormat("MM-dd-yy");
SimpleDateFormat sdf2 = new SimpleDateFormat("MM-dd-yyyy");
Date myDate = null;
try {
myDate = sdf1.parse(dateIn);
System.out.println("ONE");
} catch (ParseException e) {
try {
myDate = sdf2.parse(dateIn);
System.out.println("TWO");
} catch (ParseException e1) {
System.out.println("Date Format Error");
}
}
System.out.println(myDate);
}
June 15th, 2007 at 7:28 pm
Why does it work? 'cause SimpleDateFormat has the ability to deal with Medieval dates!
Thus you need to explicitly check for that.
try {
Date date = sdf.parse(str);
cal.setTime(date);
int year = cal.get(Calendar.YEAR);
if (year
June 18th, 2007 at 9:00 am
wrt your regexp example:
//given String input, String regex:
input.matches(regex) is a convenience method for:
Pattern.matches(regex, input)
which in turn is short for:
Pattern.compile(regex).matcher(input).matches()
If you're looking for an occurrence as opposed to matching against the entire regex, use:
Pattern.compile(regex).matcher(input).find()
And of course there's no reason not to cache the compiled Pattern in a real-world application.
Leave a Reply