Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert SimpleDateFormat to DateTimeFormatter

So when trying to replace some legacy code using SimpleDateFormat and Date, to use java.time.DateTimeFormatter and LocalDate I ran into a problem. The two date formats are not equivalent. At this point I must say I know the two date types are not the same but the scenario I am in means I never care about the time aspect so can ignore it.

public Date getDate(String value) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
    try {
        return dateFormat.parse(value);
    } catch (ParseException e) {
        return null;
    }
}

public LocalDate getLocalDate(String value) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
    try {
        return LocalDate.parse(value, formatter);
    } catch (DateTimeParseException e) {
        return null;
    }
}

public void testDates() {
    getDate("03/07/2016");               // Sun Jul 03 00:00:00 BST 2016
    getDate("3/7/2016");                 // Sun Jul 03 00:00:00 BST 2016
    getDate("3/7/2016 00:00:00");        // Sun Jul 03 00:00:00 BST 2016
    getDate("3/7/2016 00:00:00.0+0100"); // Sun Jul 03 00:00:00 BST 2016
    getDate("3/7/2016T00:00:00.0+0100"); // Sun Jul 03 00:00:00 BST 2016

    getLocalDate("03/07/2016");               // 2016-07-03
    getLocalDate("3/7/2016");                 // null
    getLocalDate("3/7/2016 00:00:00");        // null
    getLocalDate("3/7/2016 00:00:00.0+0100"); // null
    getLocalDate("3/7/2016T00:00:00.0+0100"); // null
}

As you can see when the same pattern is used in both formatters the DateTimeFormatter ends up producing nulls where you'd expect to see dates equivalent to that of SDF. In this scenario I would expect the unrequired data to be dropped but it isn't.

So, how do we create a robust date/time parser?!

like image 751
Remlap21 Avatar asked Mar 20 '17 12:03

Remlap21


People also ask

What is the difference between DateTimeFormatter and SimpleDateFormat?

DateTimeFormatter is a replacement for the old SimpleDateFormat that is thread-safe and provides additional functionality.

Is SimpleDateFormat deprecated?

Class SimpleDateFormat. Deprecated. A class for parsing and formatting dates with a given pattern, compatible with the Java 6 API.

Is DateTimeFormatter thread-safe?

Yes, it is: DateTimeFormat is thread-safe and immutable, and the formatters it returns are as well. Implementation Requirements: This class is immutable and thread-safe.

What is DateTimeFormatter Iso_date_time?

ISO_DATE_TIME. The ISO-like date-time formatter that formats or parses a date-time with the offset and zone if available, such as '2011-12-03T10:15:30', '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30+01:00[Europe/Paris]'. static DateTimeFormatter.


1 Answers

So there may be other answers to this but what I came up caters for the most extreme case I have. Firstly I reduced dd/MM to d/M. This denotes the minimum number of expected characters so will parse double digits completely fine. Note you could also use new DateTimeFormatterBuilder().parseLenient() but this seemed unnecessary.

Secondly I decided to use the optional clause in the format pattern itself. This allows you to specify which parts may not be provided which is exactly the case I was trying to solve.

Leaving us with:

DateTimeFormatter.ofPattern("d/M/yyyy[' ']['T'][H:mm[:ss[.S]]][X]");

This will now handle providing a date with or without time including a T separator, seconds, millis and zone offset.

With any luck this helps someone else!

private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy[' ']['T'][H:mm[:ss[.S]]][X]");

public LocalDate getRobustLocalDate(String value) {
    try {
        return LocalDate.parse(value, formatter);
    } catch (DateTimeParseException e) {
        return null;
    }
}

@Test
public void testDates() {
    getRobustLocalDate("03/07/2016");               // 2016-07-03
    getRobustLocalDate("3/7/2016");                 // 2016-07-03
    getRobustLocalDate("3/7/2016 00:00:00");        // 2016-07-03
    getRobustLocalDate("3/7/2016 00:00:00.0+0100"); // 2016-07-03
    getRobustLocalDate("3/7/2016T00:00:00.0+0100"); // 2016-07-03
}
like image 63
Remlap21 Avatar answered Sep 17 '22 12:09

Remlap21