Як показав @Maglob, основним підходом є перевірка перетворення з рядка на дату за допомогою SimpleDateFormat.parse . Це вловить недійсні комбінації день / місяць, як 2008-02-31.
Однак на практиці цього буває досить рідко, оскільки SimpleDateFormat.parse надзвичайно ліберальний. Існує дві поведінки, які можуть вас турбувати:
Недійсні символи у рядку дат.
На диво, наприклад, 2008-02-2x буде "передаватися" як дійсну дату з локальним форматом = "рррр-ММ-дд". Навіть коли isLenient == false.
Роки: 2, 3 або 4 цифри?
Можливо, ви також захочете застосувати 4-значні роки, а не дозволяти поведінку SimpleDateFormat за замовчуванням (що буде інтерпретувати "12-02-31" по-різному, залежно від того, чи був ваш формат "yyyy-MM-dd" або "yy-MM-dd" )
Суворе рішення зі стандартною бібліотекою
Отже, повний рядок тестування дати може виглядати так: комбінація регулярного виразу, а потім примусове перетворення дати. Фокус у регулярному виразі полягає в тому, щоб зробити його привабливим для місцевості.
Date parseDate(String maybeDate, String format, boolean lenient) {
Date date = null;
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() ) {
SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance();
sdf.applyPattern(format);
sdf.setLenient(lenient);
try { date = sdf.parse(maybeDate); } catch (ParseException e) { }
}
return date;
}
Date date = parseDate( "21/5/2009", "d/M/yyyy", false);
Зверніть увагу, що регулярний вираз передбачає, що рядок формату містить лише день, місяць, рік та символи-роздільники. Окрім цього, формат може бути у будь-якому мовному форматі: "д / ММ / рр", "рррр-ММ-дд" тощо. Рядок формату для поточної мови можна отримати таким чином:
Locale locale = Locale.getDefault();
SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale );
String format = sdf.toPattern();
Joda Time - краща альтернатива?
Я нещодавно чув про час йоди і думав порівняти. Два моменти:
- Виглядає краще суворо ставитись до неприпустимих символів у рядку дати, на відміну від SimpleDateFormat
- Поки що не бачу способу застосувати до нього 4-значний рік (але, мабуть, для цього ви можете створити власний DateTimeFormatter )
Це досить просто у використанні:
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;
}