Reputation: 12670
I'm trying to parse rubbish date values out of IPTC metadata. The format is supposed to be yyyyMMdd
but in some situations it isn't. A particular value I have found is "Tue Jan 05 00:00:00 AEDT 2016"
.
If I try to parse this using Joda's DateTimeFormatter
:
DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss Z yyyy")
.parseLocalDate("Tue Jan 05 00:00:00 AEDT 2016");
This gives me an error:
java.lang.IllegalArgumentException: Invalid format: "Tue Jan 05 00:00:00 AEDT 2016" is malformed at "AEDT 2016"
I have tried the following zone symbols:
I realise that the docs do say that DateTimeFormatter
can't parse time zones. I also realise that these short time zone names are ambiguous. But in this situation I'm only trying to get out a LocalDate
, so all I really want is the month, day and year. (Notice how the hour, minute and second are also zero?)
I would rather not have to regex crap out of the middle of the string before passing it off if possible, because the thing I'm passing this formatter off to expects a DateTimeFormatter
at present.
Is there a way to specify some kind of arbitrary pattern of junk to throw away when parsing? I can't seem to find it in the API, but that doesn't necessarily mean it isn't there.
Upvotes: 2
Views: 2039
Reputation: 54781
So the problem is the huge interface of DateTimeFormatter
which prevents you writing your own implementation or decorator easily.
...the thing I'm passing this formatter off to expects a
DateTimeFormatter
at present.
Is it out of the question to refactor the framework (the "thing") like so:
Step 1: Create a new interface:
public interface LocalDateTimeParser {
LocalDate parseLocalDate(String text);
}
Step 2: Create an adaptor:
public final class DateTimeFormatterAdapter implements LocalDateTimeParser {
private final DateTimeFormatter adaptee;
public DateTimeFormatterAdapter(DateTimeFormatter adaptee){
this.adaptee = adaptee;
}
public LocalDate parseLocalDate(String text){
return adaptee.parseLocalDate(text);
}
}
Step 2: Reference LocalDateTimeParser
in your framework where only local parsing is required and wrap the existing DateTimeFormatter
in an adapter.
Step 3: Now you are free to write your own LocalDateTimeParser
implementation with regex pre processing to strip the timezone and pass the rest to a DateTimeFormatter
.
Upvotes: 0
Reputation: 12670
I'll post my own message workaround in the meantime, which uses a mix of existing format patterns plus a custom parser to throw away the time zone.
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("EEE MMM dd HH:mm:ss ")
.append(DateTimeFormat.forPattern("Z").getPrinter(), new DiscardTimeZoneSymbolParser())
.appendPattern(" yyyy")
.toFormatter();
LocalDate localDate = formatter.parseLocalDate("Tue Jan 05 00:00:00 AEDT 2016");
And then:
public class DiscardTimeZoneSymbolParser implements DateTimeParser {
@Override
public int estimateParsedLength() {
return 4;
}
@Override
public int parseInto(DateTimeParserBucket bucket, @NonNls String text, int position) {
for (int positionFromStart = 0; positionFromStart < 4; positionFromStart++, position++) {
boolean match;
if (position >= text.length()) {
match = false;
} else {
@NonNls
char ch = text.charAt(position);
match = ch >= 'A' && ch <= 'Z';
}
if (!match) {
if (positionFromStart >= 3) { // require 3 characters
return position;
} else {
return ~position;
}
}
}
return position;
}
}
Upvotes: 3
Reputation: 20885
You can use the parsing facilities in java.text
:
DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.ENGLISH);
df.setLenient(false);
Date date = df.parse("Tue Jan 05 00:00:00 AEDT 2016");
and then transform the java.util.Date
in the Joda LocalDate
. Note that:
Upvotes: 0