Domanda

Ho una stringa che rappresenta una data nella lingua francese : 09-ott-08:

Ho bisogno di analizzare quella stringa, quindi ho pensato a questo SimpleDateFormat:

String format2 = "dd-MMM-yy";

Ma ho un problema con la parte del mese, che sembra essere prevista con un punto finale:

df2.format(new Date());

mi dà:

 28-oct.-09

Qual è ora il modo migliore per far capire SimpleDateFormat (" 09-ott-08 ")?

Codice completo:

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

Questo mi dà: java.text.ParseException: data non analizzabile: " 09-ott-08 "

E se poi provo ad accedere:

df2.format(new Date()); 

Ricevo: 28-ott-09

È stato utile?

Soluzione

Questo sembra funzionare:

    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")));

Modifica: sembra che St. Shadow mi abbia battuto.

Altri suggerimenti

Puoi semplicemente rimuovere ". " ;:

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

Modifica, per quanto riguarda la risposta limone :

Sembra essere un problema con la formattazione quando si usa il Francese Locale. Pertanto, suggerisco di utilizzare semplicemente la rimozione . come ho spiegato.

In effetti, il seguente codice:

    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));

visualizza il seguente output:

28-oct.-09
28-Oct-09

Modifica di nuovo

Ok, ho subito il tuo problema.

Non so davvero come risolvere questo problema senza prima elaborare la tua String. L'idea è di sostituire il mese nella stringa originale con un mese completo:

        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);

Sono d'accordo, è terribile, ma non vedo altre soluzioni se usi le classi SimpleDateFormat e Date .

Un'altra soluzione è quella di utilizzare una libreria reale di data e ora anziché quella originale di JDK, come Joda Time .

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

Output 28-Oct-09

Non vedo punti, signore. Hai provato a ricontrollare le tue stampe? Forse hai inserito accidentalmente un . accanto al tuo MMM ?


Stai ricevendo java.text.ParseException: data non analizzabile: " 09-ott-08 " poiché " 09-ott-08 " non corrisponde la formattazione di Locale.FRENCH usa la localizzazione predefinita (credo negli Stati Uniti) o aggiungi un . accanto al tuo oct

Ok, quindi prova & # 171; forza bruta & # 187; :)

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

Vediamo se il framework java.time può aiutarti.

Informazioni su java.time

Il java.time framework incorporato in Java 8 e versioni successive soppianta le fastidiose vecchie classi java.util.Date/.Calendar. Le nuove lezioni sono ispirate al Joda-Time di grande successo, inteso come suo successore, simile nel concetto ma riprogettato. Definito da JSR 310 . Esteso dal progetto ThreeTen-Extra . Vedi il Tutorial .

LocalDate

A differenza delle vecchie classi, java.time offre Classe LocalDate per rappresentare un valore di sola data, senza ora del giorno o fuso orario.

Abbreviazioni francesi

Dai un'occhiata a cosa si aspettano i formattatori in java.time per i nomi dei mesi abbreviati in en Fran & # 231; ais .

Siamo in grado di eseguire il ciclo Month enum per ottenere un elenco di mesi. Questo enum offre il getDisplayName per generare un nome localizzato del mese. Questo codice dimostra che il metodo produce lo stesso output del formattatore 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.

Troviamo un mix di ortografia di 3 e 4 lettere. I nomi più lunghi sono abbreviati in quattro caratteri più un punto ( FULL STOP ). Quattro mesi hanno nomi abbastanza brevi da essere usati senza abbreviazione: mars , mai , juin , ao & # 251; t .

Quindi, come discusso nelle altre Risposte, nessuna soluzione semplice.

Correggi l'origine dati

Il mio primo suggerimento è di correggere l'origine dati. Apparentemente tale fonte non riesce a seguire le regole francesi corrette per l'abbreviazione. Yale concorda con la comprensione del francese di Java 8. A proposito, se aggiustare la tua fonte di dati ti consiglio vivamente di usare anni a quattro cifre come due che portano a non avere fine alla confusione e all'ambiguità.

Correggi input

Naturalmente la fonte potrebbe essere fuori dal tuo controllo / influenza. In quel caso, come con le altre Risposte, potresti dover fare una sostituzione a forza bruta piuttosto che tentare qualsiasi intelligenza. D'altra parte, se l'unico problema con il tuo input è semplicemente la mancanza del punto (FULL STOP), allora potresti soft-code usando l'enum Month anziché hard-code i valori impropri.

Farei un tentativo iniziale di analisi. Trap per DateTimeParseException , prima di tentare una correzione. Se viene generata l'eccezione, correggi l'input.

Per correggere l'input, prova ogni mese dell'anno eseguendo il ciclo del possibile set di istanze enum. Per ogni mese, ottieni il nome abbreviato. Rimuovi il punto (FULL STOP) da quell'abbreviazione, affinché corrisponda a quello che sospettiamo sia il nostro valore in entrata improprio. Prova per vedere se in effetti è una corrispondenza per l'input. In caso contrario, vai al mese prossimo.

Quando otteniamo una corrispondenza, correggiamo l'input in modo che sia abbreviato correttamente per le regole di Locale (regole francesi nel nostro caso). Quindi analizzare l'input fisso. Questo sarebbe il nostro secondo tentativo di analisi, dato che abbiamo fatto un tentativo iniziale in alto. Se questo secondo tentativo fallisce, qualcosa è molto sbagliato, come indicato nel FIXME: visto qui. Ma normalmente questo secondo tentativo di analisi avrà esito positivo e possiamo uscire dal ciclo for dell'enum Month .

Infine, puoi verificare il successo testando se il risultato è ancora il valore del flag fasullo impostato inizialmente ( 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).

Scarica su console.

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

successo: vero. input: 09-ott-08 & # 8594; localDate: 09-10-2008 & # 8594; formattato: 09-ott-08 & # 8594; outputImproprio: 09-ott-08

Stavo avendo lo stesso problema (francese e punti extra) e credo che il modo giusto per risolvere questo problema sia sovrascrivendo globalmente il locale francese in questo modo:

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'oggetto francese monthsShort originale ha i punti simili janv._févr._mars_avr ._... , quindi li stiamo semplicemente rimuovendo.

Ecco un link a documenti dove puoi controllare cosa può essere sovrascritto .

Nota che non abbiamo bisogno di passare un oggetto locale completo se vogliamo solo sovrascrivere ad es .: monthsShort .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top