79

I'm parsing third party log files containing date/time using Joda. The date/time is in one of two different formats, depending on the age of the log files I'm parsing.

Currently I have code like this:

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

This works but contravenes Joshua Bloch's advice from Effective Java 2nd Edition (Item 57: Use exceptions only for exceptional conditions). It also makes it hard to determine if an IllegalArgumentException occurs due to a screwed up date/time in a log file.

Can you suggest a nicer approach that doesn't misuse exceptions?

JodaStephen
  • 60,927
  • 15
  • 95
  • 117
Steve McLeod
  • 51,737
  • 47
  • 128
  • 184

3 Answers3

149

You can create multiple parsers and add them to the builder by using DateTimeFormatterBuilder.append method:

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" );
despot
  • 7,167
  • 9
  • 44
  • 63
btiernay
  • 7,873
  • 5
  • 42
  • 48
  • 1
    This works perfectly. I guess JodaStephen meant this to, but when I tried to do things according to his instructions the parsing failed. – Steve McLeod Dec 02 '10 at 15:19
  • 2
    This does not work for for example '5-5-5' and '5-5-2005' if you want both dd-MM-yy and dd-MM-yyyy (could not parse exception). Later I found out that dd-MM-yy also parses dd-MM-yyyy just fine, so that resolved my problem. – Steven Mar 13 '14 at 14:04
  • 1
    Strangely, despite the variety of `append` overloads, this is the only one that doesn't throw an exception when given conflicting formats. – shmosel Feb 16 '18 at 23:06
17

Joda-Time supports this by allowing multiple parsers to be specified - DateTimeFormatterBuilder#append

Simply create your two formatters using a builder and call toParser() on each. Then use the builder to combine them using append.

JodaStephen
  • 60,927
  • 15
  • 95
  • 117
  • 4
    Whoa! Answered directly from the man himself! Love your work Stephen. – Steve McLeod Jul 23 '10 at 12:31
  • 3
    Hmm, I tried this, but Joda-Time then seems to expect the string being parsed to match a pattern that consists of BOTH the patterns appended together, rather than one OR the other. – Steve McLeod Jul 23 '10 at 12:52
  • Perhaps the forum is a better location to see if this is a bug - http://sourceforge.net/projects/joda-time/forums/forum/337835 – JodaStephen Jul 26 '10 at 09:40
7

Unfortunately I don't believe Joda Time has any such capabilities. It would be nice to have a "tryParseDateTime" method, but it doesn't exist.

I suggest you isolate this behaviour into your own class (one which takes a list of patterns, and will try each in turn) so that the ugliness is only in one place. If this is causing performance issues, you might want to try to use some heuristics to guess which format to try first. For example, in your case if the string starts with a digit then it's probably the first pattern.

Note that DateTimeFormatters in Joda Time are conventionally immutable - you shouldn't be creating a new one each time you want to parse a line. Create them once and reuse them.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • This answer gives a sense to my comment. I'm pretty satisfied :) I'm still a beginner, so I would not give it as answer – sly7_7 Jul 22 '10 at 09:26
  • Thanks Jon. I knew about DateTimeFormatters being immutable, but for the sake of brevity in my code example created them explicitly. There are no intolerable performance issues, so I think I'll do what you suggest and create a class to hide the ugliness. – Steve McLeod Jul 22 '10 at 09:29
  • Boo Java for lack of TryParse functions like DotNet. The lack of tryParse routines and generic type erasure are my two biggest gripes. https://docs.oracle.com/javase/tutorial/java/generics/erasure.html – granadaCoder Oct 03 '18 at 13:20