web-dev-qa-db-fra.com

Java 8 LocalDateTime analyse une date non valide

Je voulais valider la date du côté client alors j'ai écrit le code suivant. Mais au lieu d’obtenir une exception, je reçois un objet de date approprié pour la chaîne de date du 31 février, qui est clairement une date invalide. 

public class Test {

    public static void main(String[] args) {
        String dateFormat = "HH:mm:ss MM/dd/yyyy";
        String dateString = "11:30:59 02/31/2015";
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat, Locale.US);
        try {
            LocalDateTime date = LocalDateTime.parse(dateString, dateTimeFormatter);
            System.out.println(date);
        } catch (Exception e) {
            // Throw invalid date message
        }
    }
}

Sortie : 2015-02-28T11: 30: 59

Est-ce que quelqu'un sait pourquoi LocalDateTime analyse cette date au lieu de lancer une exception?.

15
Zeeshan

Vous avez juste besoin d'un ResolverStyle .

L'analyse d'une chaîne de texte se déroule en deux phases. La phase 1 est une analyse de base du texte en fonction des champs ajoutés au générateur. La phase 2 résout les paires champ-valeur analysées en objets date et/ou heure. Ce style est utilisé pour contrôler le déroulement de la phase 2 de la résolution.

Exemple de code - où withResolverStyle(ResolverStyle.STRICT) est le changement important, ainsi que l'utilisation de uuuu plutôt que yyyy (où uuuu est "année" et "yyyy" est "année de l'ère" et donc ambiguë):

import Java.time.*;
import Java.time.format.*;
import Java.util.*;

public class Test {

    public static void main(String[] args) {
        String dateFormat = "HH:mm:ss MM/dd/uuuu";
        String dateString = "11:30:59 02/31/2015";
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter
            .ofPattern(dateFormat, Locale.US)
            .withResolverStyle(ResolverStyle.STRICT);
        try {
            LocalDateTime date = LocalDateTime.parse(dateString, dateTimeFormatter);
            System.out.println(date);
        } catch (DateTimeParseException e) {
            // Throw invalid date message
            System.out.println("Exception was thrown");
        }
    }
}
27
Jon Skeet

Java 8 DateTimeFormatter utilise yyyy pour signifier YEAR_OF_ERA et uuuu pour signifier YEAR. Vous devez modifier votre chaîne de modèle comme suit:

String dateFormat = "HH:mm:ss MM/dd/uuuu";

Par défaut, DateTimeFormatter utilise le style de résolveur SMART, mais vous souhaitez qu'il utilise le style de résolveur STRICT. Modifiez votre code d'initialisation dateTimeFormatter comme suit:

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat, Locale.US)
                                                       .withResolverStyle(ResolverStyle.STRICT);
8
Palamino

Ce n'est pas arrondi. Février n'a jamais eu 31 jours et il est impossible d'utiliser un objet de validation date/heure pour représenter un jour inexistant.

En conséquence, il prend l'entrée non valide et vous donne la meilleure approximation possible de la date correcte (la dernière date de février de cette année).

SimpleDateFormat hérite de DateFormat qui contient une méthode setLenient(boolean value). Je m'attendrais à ce que si vous appeliez setLenient(true) avant l'analyse, il se plaindrait davantage, comme indiqué dans les javadocs .

3
Edwin Buck
try {
    SimpleDateFormat df = new Java.text.SimpleDateFormat("HH:mm:ss MM/dd/yyyy");
    df.setLenient(false);
    System.out.println(df.parse("11:30:59 02/29/2015"));
} catch (Java.text.ParseException e) {
  System.out.println(e);
}

J'ai trouvé une solution pour reconnaître la date comme date valide avec DateFormat.setLenient (boolean) . Si vous essayez d’analyser une date non valide, une exception d’analyse sera levée.

Modifier:

Java 8, mais cela déclenchera une exception si un mois n'est pas compris entre 1 et 12, si un jour est supérieur à 32. Ne fonctionne pas exactement. Mais pendant des mois, ça marche.

try {
TemporalAccessor ta = DateTimeFormatter.ofPattern("HH:mm:ss MM/dd/yyyy").parse("11:30:59 02/32/2015");
} catch (Exception e) {
System.out.println(e);
}

Sortie:

Java.time.format.DateTimeParseException: Text '11:30:59 02/32/2015' could not be
 parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 32
2
SatyaTNV

LocalDateTime.parse ne génère une erreur que si la chaîne transmise contient des caractères non valides, un nombre de jours supérieur à 31 ou un mois supérieur à 12.

Par exemple, si vous avez modifié votre code en tant que tel:

String dateString = "11:30:59 0zz2/31/2015";

une exception serait levée à cause des caractères 'zz' invalides dans la date donnée. Quant à savoir pourquoi c'est "arrondi" la date pour ainsi dire, que je ne sais pas.

Source: https://docs.Oracle.com/javase/8/docs/api/Java/time/LocalDateTime.html#parse-Java.lang.CharSequence-

0
jste89