IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

SimpleDateFormat, Windows et les locales


Sujet :

Langage Java

  1. #1
    Membre chevronné

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Points : 1 894
    Points
    1 894
    Par défaut SimpleDateFormat, Windows et les locales
    Bonjour à tous,

    j'ai un problème lié au formatage de date au format Année / Semaine.

    Je suis obligé de faire fonctionner SimpleDateFormat pour cela (ETL Talend qui génère du code Java).

    Le problème est assez simple : je me suis aperçu d'un souci de formatage de date au format Année / Semaine ; en creusant, je pense avoir identifié qu'il s'agit d'un souci de locale, mais je n'arrive pas à mettre le doigt sur un élément du problème final.

    J'ai reproduit le souci avec un petit code Java assez simple que voici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    import java.sql.Date;
    import java.util.Locale;
    import java.util.Calendar;
    import java.util.TimeZone;
    import java.text.SimpleDateFormat;
    import java.text.DateFormat;
    import java.text.ParseException;
     
    import java.time.LocalDate;
    import java.time.temporal.WeekFields;
     
    public class TestDate {
        public static void main(String args[]) throws ParseException {
            Locale currentLocale = Locale.getDefault();
     
            System.out.println(System.getProperty("java.vendor"));
            System.out.println(System.getProperty("java.version"));
            System.out.println("==============");
            System.out.printf("%20s = %s%n", "getDisplayLanguage", currentLocale.getDisplayLanguage());
            System.out.printf("%20s = %s%n", "getDisplayCountry", currentLocale.getDisplayCountry());
     
            System.out.printf("%20s = %s%n", "getLanguage", currentLocale.getLanguage());
            System.out.printf("%20s = %s%n", "getCountry", currentLocale.getCountry());
     
            System.out.printf("%20s = %s%n", "user.country", System.getProperty("user.country"));
            System.out.printf("%20s = %s%n", "user.language", System.getProperty("user.language"));
            System.out.printf("%20s = %s%n", "user.variant", System.getProperty("user.variant"));
     
            System.out.println("==============");
     
            Calendar c = Calendar.getInstance();
            System.out.println("1st day of week / minimal days in 1st week : " + c.getFirstDayOfWeek() + " / " + c.getMinimalDaysInFirstWeek());
     
            System.out.println("==============");
     
            LocalDate date1 = LocalDate.of(2020, 12, 31);
            LocalDate date2 = LocalDate.of(2021, 1, 1);
     
            DateFormat df_date = new java.text.SimpleDateFormat("dd/MM/yyyy");
            DateFormat df_week = new java.text.SimpleDateFormat("YYYY-ww");
     
            System.out.printf("%20s | %10s | %10s%n", "", df_date.format(java.sql.Date.valueOf(date1)), df_date.format(java.sql.Date.valueOf(date2)));
            System.out.printf("%20s | %10s | %10s%n", "SimpleDateFormat", df_week.format(java.sql.Date.valueOf(date1)), df_week.format(java.sql.Date.valueOf(date2)));
     
            System.out.printf("%20s | %7d-%02d | %7d-%02d%n", "WeekFields",
                                            date1.get(WeekFields.ISO.weekBasedYear()), date1.get(WeekFields.ISO.weekOfWeekBasedYear()),
                                            date2.get(WeekFields.ISO.weekBasedYear()), date2.get(WeekFields.ISO.weekOfWeekBasedYear()));
     
        }
    }
    Je le lance 2 fois avec des paramètres JVM différents (je force les arguments -Duser.language=en -Duser.country=US -Duser.variant= dans le second lancement pour reproduire le premier) mais sur la même machine (un serveur Windows configuré en US) et voici le résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    >java TestDate
    Azul Systems, Inc.
    1.8.0_282
    ==============
      getDisplayLanguage = English
       getDisplayCountry = United States
       getDisplayVariant =
             getLanguage = en
              getCountry = US
            user.country = US
           user.language = en
            user.variant =
    ==============
    1st day of week / minimal days in 1st week : 2 / 4
    ==============
                         | 31/12/2020 | 01/01/2021
        SimpleDateFormat |    2020-53 |    2020-53
              WeekFields |    2020-53 |    2020-53
     
    >java -Duser.language=en -Duser.country=US -Duser.variant= TestDate
    Azul Systems, Inc.
    1.8.0_282
    ==============
      getDisplayLanguage = English
       getDisplayCountry = United States
       getDisplayVariant =
             getLanguage = en
              getCountry = US
            user.country = US
           user.language = en
            user.variant =
    ==============
    1st day of week / minimal days in 1st week : 1 / 1
    ==============
                         | 31/12/2020 | 01/01/2021
        SimpleDateFormat |    2021-01 |    2021-01
              WeekFields |    2020-53 |    2020-53
    D'après la première partie des logs et ce que j'ai pu glaner dans mes recherches sur le net, les locales des deux exécutions semblent strictement identiques.

    Pourtant, le résultat de l'affichage de la date au format année-semaine diffère entre les 2 lancements :
    2020-53 pour le premier contre 2021-01 pour le second
    Techniquement parlant, le résultat attendu pour une locale en_US serait d'après moi 2021-01.
    C'est d'ailleurs ce que j'obtiens dans les 2 exécutions du même programme sous Linux.

    Pourquoi, dans l'un des cas sous Windows, j'ai un calcul ISO de la semaine et pas dans l'autre cas ?
    Quelle est le paramétrage (et le log) manquant qui expliquerait cela svp ?

    Merci pour votre aide !

  2. #2
    Membre chevronné

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Points : 1 894
    Points
    1 894
    Par défaut
    Pour info, j'ai également testé avec une JDK Oracle et j'ai le même problème :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    >java TestDate
    Oracle Corporation
    1.8.0_202
    ==============
      getDisplayLanguage = English
       getDisplayCountry = United States
       getDisplayVariant =
             getLanguage = en
              getCountry = US
            user.country = US
           user.language = en
            user.variant =
    ==============
    1st day of week / minimal days in 1st week : 2 / 4
    ==============
                         | 31/12/2020 | 01/01/2021
        SimpleDateFormat |    2020-53 |    2020-53
              WeekFields |    2020-53 |    2020-53
     
    >java -Duser.language=en -Duser.country=US -Duser.variant= TestDate
    Oracle Corporation
    1.8.0_202
    ==============
      getDisplayLanguage = English
       getDisplayCountry = United States
       getDisplayVariant =
             getLanguage = en
              getCountry = US
            user.country = US
           user.language = en
            user.variant =
    ==============
    1st day of week / minimal days in 1st week : 1 / 1
    ==============
                         | 31/12/2020 | 01/01/2021
        SimpleDateFormat |    2021-01 |    2021-01
              WeekFields |    2020-53 |    2020-53

  3. #3
    Membre chevronné

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Points : 1 894
    Points
    1 894
    Par défaut
    On m'a donné une piste, SimpleDateFormat utilise une Locale par défaut qui est obtenue par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Locale.getDefault(Locale.Category.FORMAT)
    Or, cela retourne fr_FR dans un cas et en_US dans l'autre.

    Est-ce qu'il existe un paramètre de JVM pour forcer cette valeur via la ligne de commande ?

    En fait, c'est bon : quand j'ajoute les paramètres -Duser.language=en -Duser.country=US -Duser.variant= à la JVM, cette Locale est bien forcée à en/US !


    Merci !

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 19
    Points : 46
    Points
    46
    Par défaut
    Le problème doit venir du provider de Locale
    il y en a 5
    - CLDR (default)
    - HOST (OS provided)
    - SPI (Service Provider Interface)
    - COMPAT (formerly JRE)
    - JRE (alternative to JRE, but disfavored over COMPAT)

    en forcant HOST on doit se rapprocher de la configuration du serveur (fr-FR pour moi)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    D:\Temp>java -Djava.locale.providers=HOST TestDate
    Oracle Corporation
    1.8.0_281
    ==============
      getDisplayLanguage = Français
       getDisplayCountry = France
             getLanguage = fr
              getCountry = FR
            user.country = FR
           user.language = fr
            user.variant =
    ==============
    1st day of week / minimal days in 1st week : 2 / 1
    ==============
                         | 31/12/2020 | 01/01/2021
        SimpleDateFormat |    2021-01 |    2021-01
              WeekFields |    2020-53 |    2020-53

  5. #5
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Hello,

    Citation Envoyé par lennelei Voir le message
    Est-ce qu'il existe un paramètre de JVM pour forcer cette valeur via la ligne de commande ?
    On les trouve dans le code source de la classe Locale.Category :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
            FORMAT("user.language.format",
                   "user.script.format",
                   "user.country.format",
                   "user.variant.format",
                   "user.extensions.format");
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Membre chevronné

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Points : 1 894
    Points
    1 894
    Par défaut
    @sunzoo: de mon côté, ça ne change absolument rien que j'utilise l'un ou l'autre des providers.

    En fait, le problème vient simplement du fait qu'il existe 3 Locale :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Locale.getDefault();
    Locale.getDefault(Locale.Category.DISPLAY);
    Locale.getDefault(Locale.Category.FORMAT);
    Dans mon code, j'affiche la première, mais SimpleDateFormat utilise la troisième.
    Or, cette dernière diffère entre mes 2 lancements ce qui explique les différences.

    Quand je force les paramètres au niveau JVM, ça force bien les 3 et c'est la raison pour laquelle j'ai des calculs différents.

    Si je modifie le code Java par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    import java.sql.Date;
    import java.util.Locale;
    import java.util.Calendar;
    import java.util.TimeZone;
    import java.text.SimpleDateFormat;
    import java.text.DateFormat;
    import java.text.ParseException;
     
    import java.time.LocalDate;
    import java.time.temporal.WeekFields;
     
    public class TestDate {
        public static void main(String args[]) throws ParseException {
            Locale cL = Locale.getDefault();
            Locale cLD = Locale.getDefault(Locale.Category.DISPLAY);
            Locale cLF = Locale.getDefault(Locale.Category.FORMAT);
     
            System.out.println(System.getProperty("java.vendor"));
            System.out.println(System.getProperty("java.version"));
            System.out.println("==============");
            System.out.printf("%20s | %15s | %15s | %15s%n", "Locale.getDefault(.)", "", "DISPLAY", "FORMAT");
            System.out.printf("%20s | %15s | %15s | %15s%n", "getDisplayLanguage", cL.getDisplayLanguage(), cLD.getDisplayLanguage(), cLF.getDisplayLanguage());
            System.out.printf("%20s | %15s | %15s | %15s%n", "getDisplayCountry", cL.getDisplayCountry(), cLD.getDisplayCountry(), cLF.getDisplayCountry());
            System.out.printf("%20s | %15s | %15s | %15s%n", "getDisplayVariant", cL.getDisplayVariant(), cLD.getDisplayVariant(), cLF.getDisplayVariant());
            System.out.printf("%20s | %15s | %15s | %15s%n", "getLanguage", cL.getLanguage(), cLD.getLanguage(), cLF.getLanguage());
            System.out.printf("%20s | %15s | %15s | %15s%n", "getCountry", cL.getCountry(), cLD.getCountry(), cLF.getCountry());
            System.out.printf("%20s | %15s | %15s | %15s%n", "getVariant", cL.getVariant(), cLD.getVariant(), cLF.getVariant());
     
            System.out.printf("%20s = %s%n", "user.country", System.getProperty("user.country"));
            System.out.printf("%20s = %s%n", "user.language", System.getProperty("user.language"));
            System.out.printf("%20s = %s%n", "user.variant", System.getProperty("user.variant"));
     
            System.out.println("==============");
     
            Calendar c = Calendar.getInstance();
            System.out.println("1st day of week / minimal days in 1st week : " + c.getFirstDayOfWeek() + " / " + c.getMinimalDaysInFirstWeek());
     
            System.out.println("==============");
     
            LocalDate date1 = LocalDate.of(2020, 12, 31);
            LocalDate date2 = LocalDate.of(2021, 1, 1);
     
            DateFormat df_date = new java.text.SimpleDateFormat("dd/MM/yyyy");
            DateFormat df_week = new java.text.SimpleDateFormat("YYYY-ww");
     
            System.out.printf("%20s | %10s | %10s%n", "", df_date.format(java.sql.Date.valueOf(date1)), df_date.format(java.sql.Date.valueOf(date2)));
            System.out.printf("%20s | %10s | %10s%n", "SimpleDateFormat", df_week.format(java.sql.Date.valueOf(date1)), df_week.format(java.sql.Date.valueOf(date2)));
     
            System.out.printf("%20s | %7d-%02d | %7d-%02d%n", "WeekFields",
                                            date1.get(WeekFields.ISO.weekBasedYear()), date1.get(WeekFields.ISO.weekOfWeekBasedYear()),
                                            date2.get(WeekFields.ISO.weekBasedYear()), date2.get(WeekFields.ISO.weekOfWeekBasedYear()));
     
        }
    }
    J'obtiens bien une sortie cohérente (et on voit bien que la Locale FORMAT est en fr dans un cas) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    >java TestDate
    Azul Systems, Inc.
    1.8.0_282
    ==============
    Locale.getDefault(.) |                 |         DISPLAY |          FORMAT
      getDisplayLanguage |         English |         English |          French
       getDisplayCountry |   United States |   United States |          France
       getDisplayVariant |                 |                 |
             getLanguage |              en |              en |              fr
              getCountry |              US |              US |              FR
              getVariant |                 |                 |
            user.country = US
           user.language = en
            user.variant =
    ==============
    1st day of week / minimal days in 1st week : 2 / 4
    ==============
                         | 31/12/2020 | 01/01/2021
        SimpleDateFormat |    2020-53 |    2020-53
              WeekFields |    2020-53 |    2020-53
    >java -Duser.language=en -Duser.country=US -Duser.variant= TestDate
    Azul Systems, Inc.
    1.8.0_282
    ==============
    Locale.getDefault(.) |                 |         DISPLAY |          FORMAT
      getDisplayLanguage |         English |         English |         English
       getDisplayCountry |   United States |   United States |   United States
       getDisplayVariant |                 |                 |
             getLanguage |              en |              en |              en
              getCountry |              US |              US |              US
              getVariant |                 |                 |
            user.country = US
           user.language = en
            user.variant =
    ==============
    1st day of week / minimal days in 1st week : 1 / 1
    ==============
                         | 31/12/2020 | 01/01/2021
        SimpleDateFormat |    2021-01 |    2021-01
              WeekFields |    2020-53 |    2020-53

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

Discussions similaires

  1. [Windows]Supprimer les Bips de la console
    Par Alexandre T dans le forum Requêtes
    Réponses: 6
    Dernier message: 25/10/2006, 09h33
  2. Java, Windows et les accents
    Par _Mac_ dans le forum Langage
    Réponses: 3
    Dernier message: 25/01/2006, 13h10
  3. Comment le SE Windows Gère les interruptions ?
    Par elmessoussi dans le forum Windows
    Réponses: 2
    Dernier message: 16/10/2005, 23h29
  4. Erreur dans les locale settings
    Par narmataru dans le forum Debian
    Réponses: 9
    Dernier message: 16/11/2004, 20h51
  5. Gestion des message windows dans les threads
    Par billyboy dans le forum Windows
    Réponses: 5
    Dernier message: 06/10/2003, 17h25

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo