24 Stimmen

Parsing eines Datums mit kurzem Monat ohne Punkt

Ich habe einen String, der ein Datum in Französisch Schauplatz : 09-okt-08 :

Ich muss zerlegen. diese Zeichenfolge, also habe ich dieses SimpleDateFormat entwickelt:

String format2 = "dd-MMM-yy";

Aber ich habe ein Problem mit dem Monatsteil, der mit einem abschließenden Punkt erwartet zu werden scheint:

df2.format(new Date());

gibt mir :

 28-oct.-09

Was ist nun der beste Weg für mich zu machen SimpleDateFormat verstehen ("09-oct-08") ?

Vollständiger Code :

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

Dies gibt mir : java.text.ParseException: Unparseable date: "09-oct-08"

Und wenn ich dann versuche, mich anzumelden :

df2.format(new Date()); 

Ich erhalte: 28-Okt.-09

7voto

Jack Leow Punkte 21300

Das scheint zu funktionieren:

    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: Sieht aus, als wäre St. Shadow mir zuvorgekommen.

5voto

Basil Bourque Punkte 256611

Java.time

Mal sehen, ob die java.time Rahmen kann helfen.

Über java.time

En java.time Framework, das in Java 8 integriert ist und die lästigen alten java.util.Date/.Calendar-Klassen ablöst. Die neuen Klassen sind inspiriert von dem sehr erfolgreichen Joda-Time das als Nachfolger gedacht ist, vom Konzept her ähnlich, aber mit einer neuen Architektur. Definiert durch JSR 310 . Erweitert um den DreiZehn-Extra Projekt. Siehe die Tutorial .

LocalDate

Anders als die alten Klassen bietet java.time die LocalDate um einen reinen Datumswert ohne Tageszeit und Zeitzone darzustellen.

Französische Abkürzungen

Schauen Sie sich an, was die Formatierer in java.time für abgekürzte Monatsnamen in auf Französisch .

Wir können die Schleife Month enum, um eine Liste der Monate zu erhalten. Diese Aufzählung bietet die getDisplayName Methode zur Erzeugung eines lokalisierten Monatsnamens. Dieser Code zeigt, dass die Methode die gleiche Ausgabe wie der java.time formatter erzeugt.

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.

Wir finden eine Mischung aus Schreibweisen mit 3 und 4 Buchstaben. Längere Namen werden auf vier Buchstaben plus einen Punkt abgekürzt ( FULL STOP ). Vier Monate haben so kurze Namen, dass sie ohne Abkürzung verwendet werden können: mars , mai , juin , août .

Wie bereits in den anderen Antworten erwähnt, gibt es also keine einfache Lösung.

Fixieren Sie die Datenquelle

Mein erster Vorschlag ist, Ihre Datenquelle zu reparieren. Diese Quelle hält sich offensichtlich nicht an die korrekten französischen Regeln für Abkürzungen. Yale stimmt mit dem Verständnis von Französisch in Java 8 überein. Übrigens, wenn Sie Ihre Datenquelle fixieren, empfehle ich dringend, vierstellige Jahreszahlen zu verwenden, da zwei zu unendlicher Verwirrung und Mehrdeutigkeit führen.

Fixieren der Eingabe

Natürlich kann die Quelle außerhalb Ihrer Kontrolle/Einflussnahme liegen. In diesem Fall, wie auch bei den anderen Antworten, müssen Sie vielleicht eher einen Brute-Force-Ersatz durchführen, als irgendetwas Gescheites zu versuchen. Wenn das einzige Problem bei Ihrer Eingabe darin besteht, dass einfach der Punkt (FULL STOP) fehlt, können Sie den Softcode mit der Month enum zu verwenden, anstatt die unzulässigen Werte fest zu kodieren.

Ich würde einen ersten Parse-Versuch unternehmen. Trap für die DateTimeParseException bevor Sie eine Reparatur versuchen. Wenn die Ausnahme ausgelöst wird, dann korrigieren Sie die Eingabe.

Um die Eingabe zu korrigieren, probieren Sie jeden Monat des Jahres aus, indem Sie eine Schleife durch die möglichen Enum-Instanzen ziehen. Ermitteln Sie für jeden Monat seinen abgekürzten Namen. Entfernen Sie den Punkt (FULL STOP) aus dieser Abkürzung, um den vermutlich falschen Eingangswert zu ermitteln. Testen Sie, ob dies tatsächlich eine Übereinstimmung mit der Eingabe ist. Wenn nicht, fahren Sie mit dem nächsten Monat fort.

Wenn wir einen Treffer erhalten, korrigieren Sie die Eingabe so, dass sie für die Regeln des Gebietsschemas (in unserem Fall Französisch) richtig abgekürzt ist. Dann wird die korrigierte Eingabe geparst. Dies wäre unser zweiter Parse-Versuch, da wir oben einen ersten Versuch unternommen haben. Wenn dieser zweite Versuch fehlschlägt, ist etwas sehr falsch, wie in der FIXME: hier zu sehen. Aber normalerweise wird dieser zweite Parse-Versuch erfolgreich sein, und wir können aus dem for Schleife des Month enum.

Schließlich können Sie den Erfolg überprüfen, indem Sie testen, ob das Ergebnis immer noch der ursprünglich gesetzte falsche Flaggenwert ist ( 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 auf die Konsole.

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

Erfolg: true. input: 09-okt-08 localDate: 2008-10-09 formatiert: 09-okt.-08 outputImproper: 09-okt-08

3voto

Romain Linsolas Punkte 76507

Sie können einfach das "." entfernen:

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

Bearbeiten, betreffend die Zitrone Antwort:

Es scheint sich um ein Problem mit der Formatierung zu handeln, wenn das Gebietsschema Französisch verwendet wird. Ich schlage daher vor, dass Sie einfach das . Entfernung, wie ich erklärt habe.

In der Tat, der folgende Code:

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

zeigt die folgende Ausgabe an:

28-oct.-09
28-Oct-09

Erneut bearbeiten

Okay, ich habe Ihr Problem jetzt verstanden.

Ich weiß nicht, wie Sie dieses Problem lösen können, ohne vorher Ihren String zu bearbeiten. Die Idee ist, den Monat im ursprünglichen String durch einen umfassenden Monat zu ersetzen:

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

Ich stimme zu, das ist furchtbar, aber ich sehe keine andere Lösung, wenn man die SimpleDateFormat y Date Klassen.

Eine andere Lösung ist die Verwendung eines リアル Datums- und Zeitbibliothek anstelle der ursprünglichen JDK-Bibliotheken, wie z. B. Joda Zeit .

2voto

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

Ausgänge 28-Oct-09

Ich sehe keine Punkte, Sir. Haben Sie versucht, Ihre Abdrücke erneut zu überprüfen? Vielleicht haben Sie versehentlich einen . neben Ihrem MMM ?


Sie bekommen java.text.ParseException: Unparseable date: "09-oct-08" seit "09-oct-08" stimmt nicht mit der Formatierung von Locale.FRENCH entweder das Standardgebietsschema (US, glaube ich) verwenden oder eine . neben Ihrem oct

2voto

St.Shadow Punkte 1840

Ok, dann versuchen Sie es mit "roher Gewalt" :)

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X