Verwenden der Joda-API für Datum und Uhrzeit zum Parsen mehrerer Formate

76

Ich analysiere Protokolldateien von Drittanbietern, die Datum und Uhrzeit enthalten, mit Joda. Das Datum und die Uhrzeit liegen in einem von zwei verschiedenen Formaten vor, abhängig vom Alter der Protokolldateien, die ich analysiere.

Derzeit habe ich folgenden Code:

try {
    return DateTimeFormat.forPattern("yyyy/MM/dd HH:mm:ss").parseDateTime(datePart);
} catch (IllegalArgumentException e) {
    return DateTimeFormat.forPattern("E, MMM dd, yyyy HH:mm").parseDateTime(datePart);
}

Dies funktioniert, widerspricht jedoch Joshua Blochs Rat aus Effective Java 2nd Edition (Punkt 57: Verwenden Sie Ausnahmen nur für außergewöhnliche Bedingungen). Es ist auch schwierig festzustellen, ob eine IllegalArgumentException aufgrund eines fehlerhaften Datums / einer fehlerhaften Uhrzeit in einer Protokolldatei auftritt.

Können Sie einen schöneren Ansatz vorschlagen, der Ausnahmen nicht missbraucht?

Steve McLeod
quelle
Vielleicht indem Sie das Muster erraten, bevor Sie es verwenden.
Sly7_7

Antworten:

146

Sie können mehrere Parser erstellen und diese mithilfe der DateTimeFormatterBuilder.append- Methode zum Builder hinzufügen :

DateTimeParser[] parsers = { 
        DateTimeFormat.forPattern( "yyyy-MM-dd HH" ).getParser(),
        DateTimeFormat.forPattern( "yyyy-MM-dd" ).getParser() };
DateTimeFormatter formatter = new DateTimeFormatterBuilder().append( null, parsers ).toFormatter();

DateTime date1 = formatter.parseDateTime( "2010-01-01" );
DateTime date2 = formatter.parseDateTime( "2010-01-01 01" );
Übrigens
quelle
1
Das funktioniert perfekt. Ich denke, JodaStephen meinte das so, aber als ich versuchte, die Dinge gemäß seinen Anweisungen zu tun, schlug die Analyse fehl.
Steve McLeod
2
Dies funktioniert beispielsweise für '5-5-5' und '5-5-2005' nicht, wenn Sie sowohl TT-MM-JJ als auch TT-MM-JJJJ möchten (Ausnahme konnte nicht analysiert werden). Später fand ich heraus, dass TT-MM-JJ auch TT-MM-JJJJ gut analysiert, so dass mein Problem gelöst wurde.
Steven
1
Seltsamerweise ist dies trotz der Vielzahl von appendÜberladungen die einzige, die bei widersprüchlichen Formaten keine Ausnahme auslöst.
Shmosel
17

Joda-Time unterstützt dies, indem mehrere Parser angegeben werden können - DateTimeFormatterBuilder # append

Erstellen Sie einfach Ihre beiden Formatierer mit einem Builder und rufen Sie toParser()jeden auf. Verwenden Sie dann den Builder, um sie mit zu kombinieren append.

JodaStephen
quelle
4
Whoa! Direkt vom Mann selbst beantwortet! Liebe deine Arbeit Stephen.
Steve McLeod
3
Hmm, ich habe es versucht, aber Joda-Time scheint dann zu erwarten, dass die analysierte Zeichenfolge mit einem Muster übereinstimmt, das aus BEIDEN Mustern besteht, die aneinander angehängt sind, und nicht aus dem einen oder dem anderen.
Steve McLeod
Vielleicht ist das Forum ein besserer Ort, um zu sehen, ob dies ein Fehler ist - sourceforge.net/projects/joda-time/forums/forum/337835
JodaStephen
7

Leider glaube ich nicht, dass Joda Time über solche Fähigkeiten verfügt. Es wäre schön, eine "tryParseDateTime" -Methode zu haben, aber sie existiert nicht.

Ich schlage vor, Sie isolieren dieses Verhalten in Ihre eigene Klasse (eine, die eine Liste von Mustern erstellt und diese nacheinander ausprobiert), damit die Hässlichkeit nur an einer Stelle ist. Wenn dies zu Leistungsproblemen führt, sollten Sie versuchen, mithilfe einiger Heuristiken zu erraten, welches Format zuerst versucht werden soll. Wenn in Ihrem Fall die Zeichenfolge beispielsweise mit einer Ziffer beginnt, ist dies wahrscheinlich das erste Muster.

Beachten Sie, dass DateTimeFormatters in Joda Time herkömmlicherweise unveränderlich sind - Sie sollten nicht jedes Mal eine neue erstellen, wenn Sie eine Zeile analysieren möchten. Erstellen Sie sie einmal und verwenden Sie sie wieder.

Jon Skeet
quelle
Diese Antwort gibt meinem Kommentar einen Sinn. Ich bin ziemlich zufrieden :) Ich bin noch ein Anfänger, also würde ich es nicht als Antwort geben
sly7_7
Danke Jon. Ich wusste, dass DateTimeFormatters unveränderlich ist, habe sie jedoch der Kürze halber in meinem Codebeispiel explizit erstellt. Es gibt keine unerträglichen Leistungsprobleme, daher denke ich, dass ich tun werde, was Sie vorschlagen, und eine Klasse erstellen werde, um die Hässlichkeit zu verbergen.
Steve McLeod
Boo Java mangels TryParse-Funktionen wie DotNet. Das Fehlen von tryParse-Routinen und das Löschen von generischen Typen sind meine beiden größten Probleme. docs.oracle.com/javase/tutorial/java/generics/erasure.html
granadaCoder