I am supporting a common library at work that performs many checks of a given string to see if it is a valid date. The Java API, commons-lang library, and JodaTime all have
You can revert your thinking - try to fail as quickly as possible when the String definitely is no date:
nulllength is not 8 (based on your example date format!)If none of those apply, then try to parse it - preferably with a pre-made static Format object, don't create one on every method run.
EDIT after comments
Based on this neat trick, I wrote a fast validation method. It looks ugly, but is significantly faster than the usual library methods (which should be used in any standard situation!), because it relies on your specific date format and does not create a Date object. It handles the date as an int and goes on from that.
I tested the daysInMonth() method just a little bit (the leap year condition taken from Peter Lawrey), so I hope there's no apparent bug.
A quick (estimated!) microbenchmark indicated a speedup by a factor of 30.
public static boolean isValidDate(String dateString) {
if (dateString == null || dateString.length() != "yyyyMMdd".length()) {
return false;
}
int date;
try {
date = Integer.parseInt(dateString);
} catch (NumberFormatException e) {
return false;
}
int year = date / 10000;
int month = (date % 10000) / 100;
int day = date % 100;
// leap years calculation not valid before 1581
boolean yearOk = (year >= 1581) && (year <= 2500);
boolean monthOk = (month >= 1) && (month <= 12);
boolean dayOk = (day >= 1) && (day <= daysInMonth(year, month));
return (yearOk && monthOk && dayOk);
}
private static int daysInMonth(int year, int month) {
int daysInMonth;
switch (month) {
case 1: // fall through
case 3: // fall through
case 5: // fall through
case 7: // fall through
case 8: // fall through
case 10: // fall through
case 12:
daysInMonth = 31;
break;
case 2:
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) {
daysInMonth = 29;
} else {
daysInMonth = 28;
}
break;
default:
// returns 30 even for nonexistant months
daysInMonth = 30;
}
return daysInMonth;
}
P.S. Your example method above will return true for "99999999". Mine will only return true for existent dates :).