Alex Kornhauser Alex Kornhauser -4 years ago 90
Java Question

DateTimeFormatter Accept Multiple Types and Convert to One

I am trying to write a

DateTimeFormatter
that will allow me to take in multiple different string formats, and then convert the string formats to a specific type. Due to the scope of the project and the code that already exists, I cannot use a different type of formatter.

eg.
I want to accept
MM/dd/yyyy
as well as
yyyy-MM-dd'T'HH:mm:ss
but then convert both to
MM/dd/yyyy
.

Could someone suggest ideas on how to do this with the
org.joda.time.format
?

I have not found a good/working example of this online.

Answer Source

I'm using Joda-Time 2.9.7 and JDK 1.7.0_79.

You can use DateTimeFormatterBuilder.append method: it receives a printer (with a pattern used to print date/times) and an array of parsers with all possible input patterns:

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import org.joda.time.format.DateTimeParser;

// MM/dd/yyyy format
DateTimeFormatter monthDayYear = DateTimeFormat.forPattern("MM/dd/yyyy");
// array of parsers, with all possible input patterns
DateTimeParser[] parsers = {
    // parser for MM/dd/yyyy format
    monthDayYear.getParser(),
    // parser for yyyy-MM-dd'T'HH:mm:ss format
    DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss").getParser() };
DateTimeFormatter parser = new DateTimeFormatterBuilder()
    // use the monthDayYear formatter for output (monthDayYear.getPrinter()) and parsers array for input (parsers)
    .append(monthDayYear.getPrinter(), parsers)
    // create formatter (using UTC to avoid DST problems)
    .toFormatter().withZone(DateTimeZone.UTC);

// test with MM/dd/yyyy
DateTime datetime1 = parser.parseDateTime("06/14/2017");
System.out.println(parser.print(datetime1)); // 06/14/2017

// test with yyyy-MM-dd'T'HH:mm:ss
DateTime datetime2 = parser.parseDateTime("2017-06-14T10:30:40");
System.out.println(parser.print(datetime2)); // 06/14/2017

I've used DateTimeZone.UTC to avoid problems with Daylight Saving Time.

For example, in my default timezone (America/Sao_Paulo), last year (2016), DST started at October 16th: at midnight, the clocks move 1 hour ahead (so, tecnically, midnight doesn't exist at this day, because time changes from 23:59:59 to 01:00:00).

The problem is, when parsing MM/dd/yyyy format, there's no fields for hour, minute or second, and the parser sets 0 as a default value for all these fields (so the hour becomes midnight). But if I try to parse in a date where DST starts (like 10/16/2016) and don't use the UTC as above, the code throws an exception because midnight doesn't exist in that day (due to DST hour shift).

Using UTC avoids this error, as DateTimeZone.UTC has no DST effects. With this, the code works independent of your system's default timezone.

The output is:

06/14/2017
06/14/2017


PS: As you care only about the date part (day/month/year), you could also use the org.joda.time.LocalDate class. To use it, just change the last part of the code (you can use the same parser):

// test with MM/dd/yyyy
LocalDate dt1 = parser.parseLocalDate("06/14/2017");
System.out.println(parser.print(dt1)); // 06/14/2017

// test with yyyy-MM-dd'T'HH:mm:ss
LocalDate dt2 = parser.parseLocalDate("2017-06-14T10:30:40");
System.out.println(parser.print(dt2)); // 06/14/2017

The output is the same:

06/14/2017
06/14/2017

Using a LocalDate is another way to avoid problems with Daylight Saving Time (as explained above). In this case, you don't need to set UTC, because LocalDate has no timezone information.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download