Comme l'a montré @Maglob, l'approche de base consiste à tester la conversion de la chaîne de caractères en date en utilisant SimpleDateFormat.parse . Cela permettra de détecter les combinaisons jour/mois non valides, comme 2008-02-31.
Toutefois, dans la pratique, cela suffit rarement, car SimpleDateFormat.parse est extrêmement libéral. Il existe deux comportements qui peuvent vous inquiéter :
Caractères non valides dans la chaîne de date Étonnamment, 2008-02-2x "passe" comme une date valide avec le format local = "yyyy-MM-dd" par exemple. Même lorsque isLenient==false.
Années : 2, 3 ou 4 chiffres ? Vous pouvez également vouloir imposer des années à 4 chiffres plutôt que d'autoriser le comportement par défaut de SimpleDateFormat (qui interprétera "12-02-31" différemment selon que votre format était "aaaa-MM-jj" ou "aaaa-MM-jj").
Une solution stricte avec la bibliothèque standard
Ainsi, un test complet de conversion de chaîne en date pourrait ressembler à ceci : une combinaison d'expressions rationnelles, puis une conversion forcée de la date. L'astuce avec l'expression rationnelle est de la rendre adaptée aux spécificités locales.
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);
Notez que la regex suppose que la chaîne de format ne contient que le jour, le mois, l'année et les caractères de séparation. En dehors de cela, le format peut être dans n'importe quel format local : "d/MM/yy", "yyyy-MM-dd", et ainsi de suite. La chaîne de format pour la locale actuelle peut être obtenue comme suit :
Locale locale = Locale.getDefault();
SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale );
String format = sdf.toPattern();
Joda Time - Une meilleure alternative ?
J'ai entendu parler de temps joda récemment et j'ai pensé comparer. Deux points :
- Il semble être plus strict en ce qui concerne les caractères non valides dans la chaîne de date, contrairement à SimpleDateFormat.
- Je ne vois pas encore de moyen de faire respecter les années à 4 chiffres (mais je suppose que vous pourriez créer votre propre année). DateTimeFormatter à cette fin)
C'est assez simple à utiliser :
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;
}