Question

J'ai une chaîne qui représente une date en français : 09-oct-08:

Je dois analyser cette chaîne. Je suis donc parvenu à cet objet SimpleDateFormat:

String format2 = "dd-MMM-yy";

Mais j'ai un problème avec la partie mois, ce qui semble être attendu avec un point final:

df2.format(new Date());

me donne:

 28-oct.-09

Quel est maintenant le meilleur moyen pour moi de faire comprendre à SimpleDateFormat ("09-oct-08")?

Code complet:

String format2 = "dd-MMM-yy"; 
DateFormat df2 = new SimpleDateFormat(format2,Locale.FRENCH); 
date = df2.parse("09-oct-08"); 

Ceci me donne: java.text.ParseException: date imparable: "09-oct-08".

Et si j'essaie alors de me connecter:

df2.format(new Date()); 

Je reçois: le 28 octobre 2009

Était-ce utile?

La solution

Cela semble fonctionner:

    DateFormatSymbols dfsFr = new DateFormatSymbols(Locale.FRENCH);
    String[] oldMonths = dfsFr.getShortMonths();
    String[] newMonths = new String[oldMonths.length];
    for (int i = 0, len = oldMonths.length; i < len; ++ i) {
        String oldMonth = oldMonths[i];

        if (oldMonth.endsWith(".")) {
            newMonths[i] = oldMonth.substring(0, oldMonths[i].length() - 1);
        } else {
            newMonths[i] = oldMonth;
        }
    }
    dfsFr.setShortMonths(newMonths);
    DateFormat dfFr = new SimpleDateFormat(
        "dd-MMM-yy", dfsFr);

    // English date parser for creating some test data.
    DateFormat dfEn = new SimpleDateFormat(
        "dd-MMM-yy", Locale.ENGLISH);
    System.out.println(dfFr.format(dfEn.parse("10-Oct-09")));
    System.out.println(dfFr.format(dfEn.parse("10-May-09")));
    System.out.println(dfFr.format(dfEn.parse("10-Feb-09")));

Edit: On dirait que St. Shadow m'a battu.

Autres conseils

Vous pouvez simplement supprimer le ".":

df2.format(new Date()).replaceAll("\\.", ""));

Modifier, en ce qui concerne la réponse citron :

Il semble que le formatage soit problématique lors de l’utilisation de la langue locale française. Par conséquent, je vous suggère simplement d’utiliser la suppression . comme je l’ai expliqué.

En effet, le code suivant:

    String format2 = "dd-MMM-yy";
    Date date = Calendar.getInstance().getTime();
    SimpleDateFormat sdf = new SimpleDateFormat(format2, Locale.FRENCH);
    System.out.println(sdf.format(date));
    sdf = new SimpleDateFormat(format2, Locale.ENGLISH);
    System.out.println(sdf.format(date));

affiche le résultat suivant:

28-oct.-09
28-Oct-09

Modifiez à nouveau

Ok, j'ai ton problème maintenant.

Je ne sais pas vraiment comment vous pouvez résoudre ce problème sans traiter d'abord votre chaîne. L'idée est de remplacer le mois dans la chaîne d'origine par un mois complet:

        String[] givenMonths = { "jan", "fév", "mars", "avr.", "mai", "juin", "juil", "août", "sept", "oct", "nov", "déc" };
        String[] realMonths = { "janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc." };
        String original = "09-oct-08";
        for (int i = 0; i < givenMonths.length; i++) {
            original = original.replaceAll(givenMonths[i], realMonths[i]);
        }
        String format2 = "dd-MMM-yy";
        DateFormat df2 = new SimpleDateFormat(format2, Locale.FRENCH);
        Date date = df2.parse(original);
        System.out.println("--> " + date);

Je suis d'accord, c'est affreux, mais je ne vois pas d'autre solution si vous utilisez les classes SimpleDateFormat et Date .

Une autre solution consiste à utiliser une vraie bibliothèque de date et d'heure au lieu des bibliothèques JDK d'origine, telles que Heure Joda .

String format2 = "dd-MMM-yy";
Date date = Calendar.getInstance().getTime();
SimpleDateFormat sdf = new SimpleDateFormat(format2);
System.out.println(sdf.format(date));

Sorties du 28 octobre 2009

Je ne vois pas de points monsieur. Avez-vous essayé de vérifier vos impressions? Peut-être avez-vous accidentellement placé un . à côté de votre MMM ?

Vous obtenez le java.text.ParseException: date non analysable: "09-oct-08" car "09-oct-08" ne correspond pas. la mise en forme de Locale.FRENCH soit utiliser les paramètres régionaux par défaut (États-Unis, je pense), soit ajouter un . à côté de votre oct

Ok, alors essayez «force brute»:)

DateFormatSymbols dfs = new DateFormatSymbols(Locale.FRENCH);
String[] months = new String[13]
<fill with correct month names or just replace these month, that are not fully correct>
dfs.setMonths(months);
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yy", dfs);
Date nweDate = sdf.parse("09-fév-08");

java.time

Voyons si le framework java.time peut vous aider.

À propos de java.time

Le java.time Le framework intégré à Java 8 et ultérieur supplante les anciennes classes problématiques java.util.Date/.Calendar. Les nouvelles classes s’inspirent du très réussi framework Joda-Time , destiné à lui succéder, similaire à dans le concept mais re-architecturé. Défini par JSR 310 . Prolongé par le projet ThreeTen-Extra . Consultez le didacticiel .

LocalDate

Contrairement aux anciennes classes, java.time propose le LocalDate , une classe représentant uniquement une date, sans heure ni fuseau horaire.

Abréviations françaises

Examinez les attentes des formateurs de java.time pour les noms de mois abrégés dans in English .

Nous pouvons boucler le Mois enum pour obtenir une liste des mois. Cette énumération présente le getDisplayName méthode pour générer un nom localisé du mois. Ce code montre que la méthode produit le même résultat que le formateur java.time.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "dd-MMM-yyyy" ).withLocale ( Locale.FRENCH );
for ( Month month : Month.values () ) {
    LocalDate localDate = LocalDate.of ( 2015 , month.getValue () , 1 );
    String output = formatter.format ( localDate );
    String displayName = month.getDisplayName ( TextStyle.SHORT , Locale.FRENCH );
    System.out.println ( "output: " + output + " | displayName: " + displayName );// System.out.println ( "input: " + input + " → " + localDate + " → " + output );
}
output: 01-janv.-2015 | displayName: janv.
output: 01-févr.-2015 | displayName: févr.
output: 01-mars-2015 | displayName: mars
output: 01-avr.-2015 | displayName: avr.
output: 01-mai-2015 | displayName: mai
output: 01-juin-2015 | displayName: juin
output: 01-juil.-2015 | displayName: juil.
output: 01-août-2015 | displayName: août
output: 01-sept.-2015 | displayName: sept.
output: 01-oct.-2015 | displayName: oct.
output: 01-nov.-2015 | displayName: nov.
output: 01-déc.-2015 | displayName: déc.

Nous trouvons un mélange d'orthographes de 3 et 4 lettres. Les noms plus longs sont abrégés en quatre caractères plus un point ( ARRET COMPLET ) Les noms de quatre mois sont suffisamment courts pour être utilisés sans abréviation: mars , mai , juin , août .

Donc, comme indiqué dans les autres réponses, aucune solution simple.

Corrigez la source de données

Ma première suggestion est de réparer votre source de données. Il semble que cette source ne respecte pas les règles françaises appropriées en matière d’abréviations. Yale approuve la compréhension du français par Java 8. À propos, si vous corrigez votre source de données, je vous suggère fortement d'utiliser des années à quatre chiffres comme deux, ce qui ne laisse aucune confusion et ambiguïté.

Correction de l'entrée

Bien sûr, la source peut être hors de votre contrôle / influence. Dans ce cas, comme pour les autres réponses, vous devrez peut-être remplacer la force brute plutôt que de faire preuve d'intelligence. D'autre part, si le seul problème lié à votre saisie est simplement l'absence de la période (ARRÊT COMPLET), vous pouvez alors utiliser un code souple à l'aide de l'énumération Month plutôt que de coder en dur les valeurs incorrectes.

Je voudrais faire une première tentative d'analyse. Piège pour la DateTimeParseException , avant de tenter un correctif. Si l'exception est levée, corrigez l'entrée.

Pour corriger l'entrée, essayez chaque mois de l'année en bouclant le jeu possible d'instances enum. Pour chaque mois, obtenez son nom abrégé. Supprimez le point (FULL STOP) de cette abréviation pour correspondre à ce que nous pensons être notre valeur entrante incorrecte. Testez pour voir si cela correspond vraiment à l'entrée. Sinon, passez au mois prochain.

Lorsque nous obtenons une correspondance, corrigez l’entrée pour qu’elle soit correctement abrégée pour les règles Locale (les règles françaises dans notre cas). Ensuite, analysez l'entrée fixe. Ce serait notre deuxième tentative d'analyse, car nous avons fait une première tentative en haut. Si cette deuxième tentative échoue, quelque chose ne va pas du tout, comme indiqué dans le FIXME: affiché ici. Mais normalement, cette deuxième tentative d’analyse réussira et nous pourrons sortir de la boucle pour de l’énumération Month .

Enfin, vous pouvez vérifier le succès en testant si le résultat correspond toujours à la valeur fictive de l'indicateur initialement définie ( LocalDate.MIN ).

String input = "09-oct-08"; // Last two digits are Year.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "dd-MMM-yy" ).withLocale ( Locale.FRENCH );
LocalDate localDate = LocalDate.MIN; // Some folks prefer a bogus default value as a success/failure flag rather than using a NULL.
try {
    localDate = LocalDate.parse ( input , formatter );
} catch ( DateTimeParseException e ) {
    // Look for any month name abbreviation improperly missing the period (FULL STOP).
    for ( Month month : Month.values () ) {
        String abbreviation = month.getDisplayName ( TextStyle.SHORT , Locale.FRENCH );
        String abbreviationWithoutFullStop = abbreviation.replace ( "." , "" ); // Get short abbreviation, but drop any period (FULL STOP).
        String proper = "-" + abbreviation + "-";
        String improper = "-" + abbreviationWithoutFullStop + "-";
        if ( input.contains ( improper ) ) {
            String inputFixed = input.replace ( improper , proper );
            try {
                localDate = LocalDate.parse ( inputFixed , formatter );
            } catch ( DateTimeParseException e2 ) {
                // FIXME: Handle this error. We expected this second parse attempt to succeed.
            }
            break; // Bail-out of the loop as we got a hit, matching input with a particular improper value.
        }
    }
}
Boolean success =  ! ( localDate.equals ( LocalDate.MIN ) );
String formatted = formatter.format ( localDate );;
String outputImproper = formatted.replace ( "." , "" );  // Drop any period (FULL STOP).

Dump sur la console.

System.out.println ( "success: " + success + ". input: " + input + " → localDate: " + localDate + " → formatted: " + formatted + " → outputImproper: " + outputImproper );
  

succès: vrai. entrée: 09-oct-08 ? localDate: 2008-10-09 ? formaté: 09-oct.-08 ? sortieImproper: 09-oct-08

J'avais le même problème (le français et les points supplémentaires) et je pense que la bonne façon de résoudre ce problème consiste à écraser globalement la langue française comme suit:

import moment from 'moment';
moment.locale('fr', { monthsShort: 'janv_févr_mars_avr_mai_juin_juil_août_sept_oct_nov_déc'.split('_') });

L'objet français d'origine monthsShort a les points comme janv._févr._mars_avr ._... , nous les supprimons donc.

Voici un lien vers la documentation où vous pouvez vérifier ce qui peut être écrasé .

Notez que nous n'avons pas besoin de passer un objet de paramètres régionaux complet si nous voulons simplement écraser ie: monthsShort .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top