Tuesday, October 19, 2010

Clever Way to Handle SimpleDateFormat ParseException

I was having a few issues dealing with dates and XMLGregorianCalendar objects. Here's what went down.

I had a method that was parsing String dates and placing them into XMLGregorianCalendar objects. In order to get the XMLGregorianCalendar object created, you can use something similar to this code (You'll be forced to catch DatatypeConfigurationException):

GregorianCalendar gc = (GregorianCalendar) GregorianCalendar.getInstance();
DatatypeFactory dataTypeFactory = DatatypeFactory.newInstance();
XMLGregorianCalendar xmlCal = dataTypeFactory.newXMLGregorianCalendar(gc);


The above code will give you the current time in an XMLGregorianCalendar object. Unfortunately I needed to accept a String date (like: 6/10/2010 5:40:30 PM) and use that instead of the current time.

The way you do this is the following (you'll be forced to catch ParseException AND DatatypeConfigurationException):

Date date = null;
SimpleDateFormat dateFormat = new SimpleDateFormat("M/dd/yyyy hh:mm:ss a")
GregorianCalendar gc = (GregorianCalendar) GregorianCalendar.getInstance();
date = dateFormat.parse(
"6/10/2010 5:40:30 PM");
gc.setTime(date);
DatatypeFactory dataTypeFactory = DatatypeFactory.newInstance();
XMLGregorianCalendar xmlCal = dataTypeFactory.newXMLGregorianCalendar(gc);


The issue was, different dates were coming back in different formats (crappy but I don't control the String passed in). So one date would be 6/10/2010 5:40:30 AM and another would be 7/11/11 5:40. When the method tried to parse a date without an AM/PM specifier, ParseException would be thrown. Very lame.

The way I've come up with to handle this is to place several SimpleDateFormat objects in a list and order them most specific to least specific (the term granularity is popping up in my mind). You can add as many SimpleDateFormat objects to the list with different patterns as you'd like.

Here is my complete example code that handles this:

private XMLGregorianCalendar getXmlGregorianCalendarFromString(
String stringDate)
{
XMLGregorianCalendar xmlCal = null;
GregorianCalendar gc = (GregorianCalendar) GregorianCalendar
.getInstance();
Date date = null;
DatatypeFactory dataTypeFactory = null;

List dateFormatsList = new ArrayList();
dateFormatsList.add(new SimpleDateFormat("M/dd/yyyy hh:mm:ss a"));
dateFormatsList.add(new SimpleDateFormat("M/dd/yyyy hh:mm:ss"));
dateFormatsList.add(new SimpleDateFormat("M/dd/yyyy hh:mm"));

for (SimpleDateFormat dateFormat : dateFormatsList)
{
try
{
date = dateFormat.parse(stringDate);
gc.setTime(date);
dataTypeFactory = DatatypeFactory.newInstance();
xmlCal = dataTypeFactory.newXMLGregorianCalendar(gc);
// If we've made it here we have everything we need to proceed
// so break from the loop
logger.warn("Successfully parsed the date: " + stringDate
+ " with the format: " + dateFormat.toPattern());
break;
}
catch (ParseException e)
{
logger.warn("Failed to parse the incoming date: " + stringDate
+ " given the format: " + dateFormat.toPattern()
+ " attempting another date format. ");
continue;
}
catch (DatatypeConfigurationException exception)
{
logger
.warn("An error occurred generating a DatatypeFactory object. ");
}
}
return xmlCal;
}


There may be some hiccups to the above method (I only need 3 possible date formats), and if a better way exists to handle multiple SimpleDateFormats let me know, but I gotta say, it's more flexible and simple than I thought it could be.

No comments:

Post a Comment