89 votes

Comment vérifier l'intégrité d'une date en Java

Je trouve curieux que le moyen le plus évident de créer Date en Java a été déprécié et semble avoir été "remplacé" par un calendrier indulgent pas si évident à utiliser.

Comment vérifier qu'une date, donnée comme une combinaison du jour, du mois et de l'année, est une date valide ?

Par exemple, 2008-02-31 (comme dans yyyy-mm-dd) serait une date invalide.

49voto

tardate Points 6809

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 :

  1. Il semble être plus strict en ce qui concerne les caractères non valides dans la chaîne de date, contrairement à SimpleDateFormat.
  2. 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;
}

40voto

Maglob Points 1271

Vous pouvez utiliser SimpleDateFormat

Par exemple, quelque chose comme :

boolean isLegalDate(String s) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    sdf.setLenient(false);
    return sdf.parse(s, new ParsePosition(0)) != null;
}

39voto

AdamC Points 5828

La méthode actuelle consiste à utiliser la classe de calendrier. Elle possède le setLenient qui validera la date et lèvera une exception si elle est hors limites, comme dans votre exemple.

J'ai oublié d'ajouter : Si vous obtenez une instance de calendrier et définissez l'heure en utilisant votre date, c'est ainsi que vous obtenez la validation.

Calendar cal = Calendar.getInstance();
cal.setLenient(false);
cal.setTime(yourDate);
try {
    cal.getTime();
}
catch (Exception e) {
  System.out.println("Invalid date");
}

7voto

Ben Points 41

Une solution alternative stricte utilisant la bibliothèque standard est d'effectuer ce qui suit :

1) Créez un SimpleDateFormat strict en utilisant votre motif

2) Tenter d'analyser la valeur saisie par l'utilisateur en utilisant l'objet format.

3) En cas de succès, reformatez la date résultant de (2) en utilisant le même format de date (de (1)).

4) Comparez la date reformatée avec la valeur originale, saisie par l'utilisateur. Si elles sont égales, alors la valeur saisie correspond strictement à votre modèle.

Ainsi, vous n'avez pas besoin de créer des expressions régulières complexes. Dans mon cas, je devais prendre en charge l'ensemble de la syntaxe des motifs de SimpleDateFormat, plutôt que d'être limité à certains types comme les jours, les mois et les années.

2voto

Dresden Sparrow Points 21

Cela fonctionne très bien pour moi. Approche suggérée ci-dessus par Ben.

private static boolean isDateValid(String s) {
    SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
    try {
        Date d = asDate(s);
        if (sdf.format(d).equals(s)) {
            return true;
        } else {
            return false;
        }
    } catch (ParseException e) {
        return false;
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X