Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 14 sur 14
  1. #1
    Membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    octobre 2009
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : octobre 2009
    Messages : 71
    Points : 48
    Points
    48

    Par défaut DateValidator (1.3.1): Souci avec le cas :format "ww/y..y" et semaine 01/2013

    Bonjour à tous,

    Dans mon application, les saisies de dates via l'IHM se font suivant le format "semaine/année", "ww/yyyy"

    en utilisant la librairie [org.apache.commons.validator.DateValidator] version jar (commons-validator-1.3.1), la validation pour la semaine "01/2013" me retourne un false !?, pas de souci avec les semaines qui suivent...

    ci-dessous un bout de code permettant de tester ce cas particulier (01/2013)

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    import org.apache.commons.validator.DateValidator;
    public class DateValidationTest {
    	public static void main(String[] args) {
     
    		final DateValidator dateValidator = DateValidator.getInstance();
    		String weekStr = "01/2012";
    		boolean validBool = (dateValidator.isValid(weekStr, "ww/yyyy", false));
    		System.out.println("resultat validation semaine [" + weekStr +"] = " + validBool);
     
                    //Cas 01/2013
                    weekStr = "01/2013";
    		validBool = (dateValidator.isValid(weekStr, "ww/yyyy", false));
    		System.out.println("resultat validation semaine [" + weekStr +"] = " + validBool);
    	}
    }

    L'execution donne ce qui suit:

    resultat validation semaine [01/2012] = true
    resultat validation semaine [01/2013] = false
    La source du problème vient de la librairie DateValidator ?

    D'avance, Merci à tous pour vos réponses.

  2. #2
    Membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    octobre 2009
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : octobre 2009
    Messages : 71
    Points : 48
    Points
    48

    Par défaut

    Meme résultat avec une version plus récente : commons-validator-1.4.0

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    import java.util.Date;
    import org.apache.commons.validator.routines.DateValidator;
     
    public class DateValidationTest {
    	public static void main(String[] args) {
     
    		final DateValidator dateValidator = DateValidator.getInstance();
     
    		String weekStr = "01/2012";
    		Date date = dateValidator.validate(weekStr, "ww/yyyy");
    		System.out.println("resultat validation semaine [" + weekStr +"] = " + date);
     
    		weekStr = "52/2012";
    		date = dateValidator.validate(weekStr, "ww/yyyy");
    		System.out.println("resultat validation semaine [" + weekStr +"] = " + date);
     
    		weekStr = "53/2013";
    		date = dateValidator.validate(weekStr, "ww/yyyy");
    		System.out.println("resultat validation semaine [" + weekStr +"] = " + date);
     
    		weekStr = "01/2013";
    		date = dateValidator.validate(weekStr, "ww/yyyy");
    		System.out.println("resultat validation semaine [" + weekStr +"] = " + date);
     
     
    		weekStr = "02/2013";
    		date = dateValidator.validate(weekStr, "ww/yyyy");
    		System.out.println("resultat validation semaine [" + weekStr +"] = " + date);
    	}
    }


    resultat validation semaine [01/2012] = Mon Jan 02 00:00:00 CET 2012
    resultat validation semaine [52/2012] = Mon Dec 24 00:00:00 CET 2012
    resultat validation semaine [53/2013] = null
    resultat validation semaine [01/2013] = null
    resultat validation semaine [02/2013] = Mon Jan 07 00:00:00 CET 2013

  3. #3
    Expert Confirmé
    Homme Profil pro
    Développeur java, access, sql server
    Inscrit en
    octobre 2005
    Messages
    1 628
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur java, access, sql server
    Secteur : Industrie

    Informations forums :
    Inscription : octobre 2005
    Messages : 1 628
    Points : 2 630
    Points
    2 630

    Par défaut

    Qu'est-ce que ça donne avec
    ·· −· −−· ·· ·−· ··− −− ·· −− ··− ··· −· −−− −·−· − ·
    · − −·−· −−− −· ··· ··− −− ·· −− ··− ·−· ·· −−· −· ··
    D'abord qu'il marche. Ensuite qu'il soit rapide. Enfin qu'il soit agréable à utiliser.
    First, make it work. Then, make it fast. Finally, make it user-friendly.
    Erst, mach', dass es funktioniert. Dann, mach', dass es schnell geht, Zum Schluss mach' es benutzerfreundlich.

  4. #4
    Membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    octobre 2009
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : octobre 2009
    Messages : 71
    Points : 48
    Points
    48

    Par défaut

    Citation Envoyé par Népomucène Voir le message
    Qu'est-ce que ça donne avec
    Bonsoir,

    ça donne null

    resultat validation semaine [53/2012] = null

    Il y a certainement un problème coté DateFormat et les méthodes de parse en dessous

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    package org.apache.commons.validator.routines;
     
    public class DateValidator extends AbstractCalendarValidator {
       public Date validate(String value, String pattern) {
             return (Date)parse(value, pattern, (Locale)null, (TimeZone)null);
         }
    ...
     
    }

    la classe
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    package org.apache.commons.validator.routines;
     
    public abstract class AbstractCalendarValidator extends AbstractFormatValidator {
     
    /**
         * <p>Checks if the value is valid against a specified pattern.</p>
         *
         * @param value The value validation is being performed on.
         * @param pattern The pattern used to validate the value against, or the
         *        default for the <code>Locale</code> if <code>null</code>.
         * @param locale The locale to use for the date format, system default if null.
         * @param timeZone The Time Zone used to parse the date, system default if null.
         * @return The parsed value if valid or <code>null</code> if invalid.
         */
        protected Object parse(String value, String pattern, Locale locale, TimeZone timeZone) {
     
            value = (value == null ? null : value.trim());
            if (value == null || value.length() == 0) {
                return null;
            }
            DateFormat formatter = (DateFormat)getFormat(pattern, locale);
            if (timeZone != null) {
                formatter.setTimeZone(timeZone);
            }
            return parse(value, formatter);
     
        }
    }

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
     
    /*
     * Licensed to the Apache Software Foundation (ASF) under one or more
     * contributor license agreements.  See the NOTICE file distributed with
     * this work for additional information regarding copyright ownership.
     * The ASF licenses this file to You under the Apache License, Version 2.0
     * (the "License"); you may not use this file except in compliance with
     * the License.  You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package org.apache.commons.validator.routines;
     
    import java.text.Format;
    import java.text.ParsePosition;
    import java.util.Locale;
    import java.io.Serializable;
     
    /**
     * <p>Abstract class for <i>Format</i> based Validation.</p>
     *
     * <p>This is a <i>base</i> class for building Date and Number
     *    Validators using format parsing.</p>
     *
     * @version $Revision: 1227719 $ $Date: 2012-01-05 18:45:51 +0100 (Thu, 05 Jan 2012) $
     * @since Validator 1.3.0
     */
    public abstract class AbstractFormatValidator implements Serializable {
     
     /**
         * <p>Parse the value with the specified <code>Format</code>.</p>
         *
         * @param value The value to be parsed.
         * @param formatter The Format to parse the value with.
         * @return The parsed value if valid or <code>null</code> if invalid.
         */
        protected Object parse(String value, Format formatter) {
     
            ParsePosition pos = new ParsePosition(0);
            Object parsedValue = formatter.parseObject(value, pos);
            if (pos.getErrorIndex() > -1) {
                return null;
            }
     
            if (isStrict() && pos.getIndex() < value.length()) {
                return null;
            }
     
            if (parsedValue != null) {
                parsedValue = processParsedValue(parsedValue, formatter);
            }
     
            return parsedValue;
     
        }
     
    }

  5. #5
    Modérateur

    Inscrit en
    septembre 2004
    Messages
    9 478
    Détails du profil
    Informations forums :
    Inscription : septembre 2004
    Messages : 9 478
    Points : 14 307
    Points
    14 307

    Par défaut

    Citation Envoyé par OrigineDeLaVie Voir le message
    Il y a certainement un problème coté DateFormat et les méthodes de parse en dessous
    Bien vu.

    Demonstration code :

    Code :
    1
    2
    3
    4
    5
    6
    7
    public static void showSimpleDateFormatProblem() throws ParseException {
      DateFormat format = new SimpleDateFormat("ww/yyyy");
      format.setLenient(false);
     
      Object date = format.parse("01/2013");
      System.out.println(date);
    }
    Il y a bien une erreur remontée, mais elle n'est pas bien claire.
    Et on se demande bien pourquoi une erreur : on a juste demandé la première semaine de 2013.

    Notons au passage que sans la ligne format.setLenient(false) on a le résultat attendu. Bon, mais on ne devrait pas avoir besoin de leniency pour la date demandée.

    Voyons ce que dit la JavaDoc de DateFormat.setLenient() : en gros c'est juste un raccourci pour getCalendar().setLenient(false).

    Nouveau code de démonstration :

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static void showSimpleDateFormatProblem2() throws ParseException {
      Calendar cal = Calendar.getInstance();
      cal.setLenient(false);
      cal.set(Calendar.WEEK_OF_YEAR, 1);
      cal.set(Calendar.YEAR, 2013);
      cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
     
      Date date = cal.getTime();
      System.out.println(date);
    }
    À nouveau une erreur, mais cette fois, le message est plus clair, et cette fois, on comprend pourquoi :
    nous avons demandé à la fois l'année 2013, la première semaine de l'année, et le lundi. Or, le lundi de la première semaine de 2013 n'est pas en 2013. Conflit. Si on veut faire des calculs de numéro de semaine avec un calendrier, il ne faut pas restreindre la leniency, puisque les semaines chevauchent les années et que leniency est contradictoire à cela.

    Si on ne demande pas de leniency, pas d'erreur, et on a le résultat voulu : le jour demandé étant l'année précédent l'année demandée, l'année est réajustée à 2012.
    Si on ne demande pas le lundi, ça dépend : le calendrier va garder le jour d'aujourd'hui, et on aura une erreur si on est lundi (dans la première semaine de 2013, seul lundi est en 2012,) et pas d'erreur un autre jour.
    SimpleDateFormat, bien sûr, renvoie toujours le premier jour concerné, ce qui signifie que derrière les rideaux il demande le lundi (pour nous autres français.)

    Mes conclusions :
    - Calendar n'a rien à se reprocher : les numéros de semaines sont ce qu'ils sont, setLenient() est ce qu'il est, les deux ne vont pas ensemble et ne doivent pas être mis ensemble.

    - SimpleDateFormat fait ce qu'il dit qu'il fait avec setLenient() : il le passe à Calendar sans se poser de question.
    Et du coup, on pourrait trouver que c'est pas le mieux : il devrait se poser des questions sur ce cas-là.
    Rappelons-nous quand même qu'un DateFormat produit des Dates, qui sont des instants dans le temps, et que le format demandé ici consiste à lire des semaines, qui ne sont pas des dates et se représentent mal comme des instants dans le temps. Les deux vont mal ensemble, et un SimpleDateFormat ne devrait sans doute pas intervenir sur cette question. Excuse qui ne va pas bien loin : parce qu'il ne marche pas mieux quand on lui indique à la fois le numéro de la semaine et un jour précis qui permet de résoudre l'ambiguïté Date <-> semaine.

    - DateValidator est essentiellement une surcouche de SimpleDateFormat. Même raisons mêmes conclusions : puisqu'il produit des Dates il est fatalement peu jouasse à gérer des semaines. En tout cas, puisque SimpleDateFormat le fait mal, il le fait mal aussi.
    Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher du poisson, il videra le lac et au bout de deux ans son village ne mangera plus jamais.
    Partagez vos connaissances, mais aussi comment s'en servir.

  6. #6
    Membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    octobre 2009
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : octobre 2009
    Messages : 71
    Points : 48
    Points
    48

    Par défaut

    Bonjour à tous et merci pour vos réponses,

    Donc, pour valider si la semaine (ww/yyyy) saisie, je devrais utiliser une autre solution qui ne s'appuie pas sur cette librairie qui est si on peut le dire boguée,

    Si c'est bien le cas (librairie boguée), comment remonter le bogue aux développeurs qui l'ont conçu ?

  7. #7
    Modérateur

    Inscrit en
    septembre 2004
    Messages
    9 478
    Détails du profil
    Informations forums :
    Inscription : septembre 2004
    Messages : 9 478
    Points : 14 307
    Points
    14 307

    Par défaut

    C'est plutôt SimpleDateFormat qui est bogué, ou du moins, qui ne fait pas les choses de façon pratique et est plutôt contre-intuitif sur le cas rencontré.

    Du coup, on pourrait dire que cette bibliothèque devrait éviter de s'en servir aussi directement. Et que le faire est un bogue, qui ne correspond pas à ce que dit sa documentation.

    Comment remonter l'erreur, leur site est clair. Issue Tracking ça me semble être le B. A. - BA
    Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher du poisson, il videra le lac et au bout de deux ans son village ne mangera plus jamais.
    Partagez vos connaissances, mais aussi comment s'en servir.

  8. #8
    Membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    octobre 2009
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : octobre 2009
    Messages : 71
    Points : 48
    Points
    48

    Par défaut

    Merci

    On peut considérer le post comme résolu.

    J'ai ouvert une nouvelle demande, ci-dessous le lien

    https://issues.apache.org/jira/browse/VALIDATOR-314


    (j'attendrais ce que ça va donner avant de marquer le post comme résolu)

  9. #9
    Expert Confirmé Sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    avril 2002
    Messages
    13 144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : avril 2002
    Messages : 13 144
    Points : 19 037
    Points
    19 037

    Par défaut

    Salut,



    Je ne pense pas que ce soit un bug de Calendar ou de DateValidator, mais juste un cas particulier qui provoque un bug avec ton pattern.

    En effet c'est ce dernier qui me semble incorrect : "ww/yyyy" il faut utiliser "ww/YYYY"

    En effet "yyyy" représente l'année en cours, tandis que "YYYY" représente l'année de la semaine en cours.

    Bien sûr dans la plupart des cas ces valeurs sont les mêmes, mais il y a des cas particulier où cela ne l'est pas.


    "01/2013" renvoi le premier jour de la première semaine de 2013, soit le 31/12/2012.
    Or avec le pattern "ww/yyyy" l'année ne correspond plus et est corrigé en 2012, ce qui provoque une erreur avec setLenient(false) et donc avec le DateValidator.

    Si tu utilises le pattern "ww/YYYY", l'année correspond bien et cela ne provoque plus aucune erreur. En effet pour le 31/12/2012, "yyyy" renvoi 2012 mais "YYYY" renvoi 2013 puisqu'il fait parti de la première semaine de 2013...



    Bref ton pattern devrait plutôt correspondre à ceci : "ww/YYYY".



    Pour l’anecdote, tu n'es pas le seul à te tromper puisqu'il semble que les ingénieurs d'Apple ont fait une erreur similaire (en anglais dans le texte) : http://arstechnica.com/apple/2013/01...elf-next-week/


    a++

  10. #10
    Modérateur

    Inscrit en
    septembre 2004
    Messages
    9 478
    Détails du profil
    Informations forums :
    Inscription : septembre 2004
    Messages : 9 478
    Points : 14 307
    Points
    14 307

    Par défaut

    Citation Envoyé par adiGuba Voir le message
    Je ne pense pas que ce soit un bug de Calendar ou de DateValidator, mais juste un cas particulier qui provoque un bug avec ton pattern.

    En effet c'est ce dernier qui me semble incorrect : "ww/yyyy" il faut utiliser "ww/YYYY"

    En effet "yyyy" représente l'année en cours, tandis que "YYYY" représente l'année de la semaine en cours.

    Bien sûr dans la plupart des cas ces valeurs sont les mêmes, mais il y a des cas particulier où cela ne l'est pas.
    Eh. Un ajout de Java 1.7, je ne l'avais pas vu.
    Du coup, c'est effectivement la façon prévue de résoudre l'ambiguïté de "vérification de date."
    Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher du poisson, il videra le lac et au bout de deux ans son village ne mangera plus jamais.
    Partagez vos connaissances, mais aussi comment s'en servir.

  11. #11
    Expert Confirmé Sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    avril 2002
    Messages
    13 144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : avril 2002
    Messages : 13 144
    Points : 19 037
    Points
    19 037

    Par défaut

    Citation Envoyé par thelvin Voir le message
    Eh. Un ajout de Java 1.7, je ne l'avais pas vu.
    En effet tiens je n'avais pas fait attention à cela...

    Du coup en Java 1.6 il faudra bidouiller pour gérer le cas.

    a++

  12. #12
    Membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    octobre 2009
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : octobre 2009
    Messages : 71
    Points : 48
    Points
    48

    Par défaut

    Bonsoir à tous,

    je n'avais pas précisé que nous sommes en java5 (contraint par notre serveur weblogic) et prévu de migrer vers java6


    Je viens d'essayer (sous jdk5) avec le Y au lieu du y et j'ai eu le résultat suivant:

    Exception in thread "main" java.lang.IllegalArgumentException: Illegal pattern character 'Y'
    at java.text.SimpleDateFormat.compile(SimpleDateFormat.java:696)
    at java.text.SimpleDateFormat.initialize(SimpleDateFormat.java:515)
    at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:464)
    at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:445)
    at org.apache.commons.validator.routines.AbstractCalendarValidator.getFormat(AbstractCalendarValidator.java:213)
    at org.apache.commons.validator.routines.AbstractCalendarValidator.parse(AbstractCalendarValidator.java:179)
    at org.apache.commons.validator.routines.DateValidator.validate(DateValidator.java:153)


    et quant à la solution de contournement mise en place, je suis passé par un split et un Integer.parseInt et une petite classe utilisant joda-time (http://joda-time.sourceforge.net/userguide.html)


    Merci à tous pour vos apports

  13. #13
    Expert Confirmé Sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    avril 2002
    Messages
    13 144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : avril 2002
    Messages : 13 144
    Points : 19 037
    Points
    19 037

    Par défaut

    Dans ce cas tu vas devoir te passer de DateValidator.
    Par exemple tu peux utiliser directement un SimpleDateFormat sans spécifier "setLenient(false)".
    Cela aura pour conséquence de "corriger" les dates invalides (par exemple "53/2012" te renverra la même chose que "01/2013", etc.)


    Si tu as vraiment besoin de vérifier que le format soit correct (et obtenir une erreur pour "53/2012" par exemple), alors le plus simple serait surement d'utiliser Calendar pour créer la date, et vérifier que le numéro de la semaine ne change pas. Par exemple :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    	public static Date getDate(int week, int year) throws ParseException {
    		Calendar calendar = Calendar.getInstance();
    		calendar.clear();	
    		calendar.set(Calendar.WEEK_OF_YEAR, week);
    		calendar.set(Calendar.YEAR, year);
     
    		if (calendar.get(Calendar.WEEK_OF_YEAR)!=week) {
    			throw new ParseException("Invalid week number", 0);
    		}
     
    		return calendar.getTime();
    	}

    a++

  14. #14
    Membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    octobre 2009
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : octobre 2009
    Messages : 71
    Points : 48
    Points
    48

    Par défaut

    Merci

+ Répondre à la discussion
Cette discussion est résolue.

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •