Jak pokazuje @Maglob, podstawowym podejściem jest przetestowanie konwersji z łańcucha do daty przy użyciu SimpleDateFormat.parse . W ten sposób zostaną wykryte nieprawidłowe kombinacje dnia i miesiąca, takie jak 2008-02-31.
Jednak w praktyce rzadko to wystarcza, ponieważ SimpleDateFormat.parse jest niezwykle liberalny. Istnieją dwa zachowania, które mogą Cię niepokoić:
Nieprawidłowe znaki w ciągu daty
Zaskakujące jest, że data 2008-02-2x „przejdzie” jako poprawna data, na przykład w formacie locale = „rrrr-MM-dd”. Nawet jeśli isLenient == false.
Lata: 2, 3 lub 4 cyfry?
Możesz także wymusić czterocyfrowe lata zamiast zezwalania na domyślne zachowanie SimpleDateFormat (które będzie interpretować „12-02-31” inaczej w zależności od tego, czy Twój format to „rrrr-MM-dd” czy „rr-MM-dd” )
Ścisłe rozwiązanie z biblioteką standardową
Tak więc pełny test ciągu do daty mógłby wyglądać następująco: połączenie dopasowania wyrażenia regularnego, a następnie wymuszona konwersja daty. Sztuczka z wyrażeniem regularnym polega na tym, aby była przyjazna dla lokalizacji.
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);
Zwróć uwagę, że wyrażenie regularne zakłada, że ciąg formatu zawiera tylko znaki dnia, miesiąca, roku i separatora. Poza tym format może być w dowolnym formacie regionalnym: „d / MM / rr”, „rrrr-MM-dd” i tak dalej. Ciąg formatu dla bieżącej lokalizacji można uzyskać w następujący sposób:
Locale locale = Locale.getDefault();
SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale );
String format = sdf.toPattern();
Joda Time - lepsza alternatywa?
Słyszałem ostatnio o czasie joda i pomyślałem, że mógłbym porównać. Dwa punkty:
- W przeciwieństwie do SimpleDateFormat wydaje się lepsze, jeśli chodzi o ścisłe przestrzeganie nieprawidłowych znaków w ciągu daty
- Nie widzę jeszcze sposobu, aby wymusić z nim 4-cyfrowe lata (ale myślę, że w tym celu możesz utworzyć własny DateTimeFormatter )
Jest dość prosty w użyciu:
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;
}