Search code examples
javadatedatetimelocaldate

Parsing a long string to a LocalDate variable


I recently had the need to take an string and convert it to a LocalDate Variable in Java; I knew this was possible and easy, but here's what I didn't see:

Context: I'm using exiftool to extract the metadata from an image via a Java Runtime Execution. The problem is that exiftool provides this next string:

2019:02:28 11:37:47-06:00

This isn't your normal Standard ISO Format (or atleast I think that it isn't). I don't know if this is using any already implemented formatting standard. So, to fix my problem, I created the next code for manual parsing:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ssZ", Locale.ENGLISH);
LocalDate date = LocalDate.parse(VAR_WITH_STR_TO_CONVERT, formatter);

I think this is a good implementation for manual conversion, but this code generates this next exception:

> Text '2019:02:28 11:37:47-06:00' could not be parsed at index 19
at java.time.format.DateTimeFormatter.parseResolved0(Unknown Source)
at java.time.format.DateTimeFormatter.parse(Unknown Source)
at java.time.LocalDate.parse(Unknown Source)

I believe that the problem is the Format String that I provide to convert, but uppon checking the DateTimeFormatter Docs, I think I have the right string.

yyyy:MM:dd HH:mm:ssZ

I'm out of ideas, does anyone know the problem here?


Solution

  • TL;DR For time zone, use XXX, not Z, to parse a value like -06:00.


    The documentation, i.e. the javadoc of DateTimeFormatter, specifies:

    Offset X and x: This formats the offset based on the number of pattern letters.

    • One letter outputs just the hour, such as '+01', unless the minute is non-zero in which case the minute is also output, such as '+0130'.
    • Two letters outputs the hour and minute, without a colon, such as '+0130'.
    • Three letters outputs the hour and minute, with a colon, such as '+01:30'.
    • Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'.
    • Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'.
    • Six or more letters throws IllegalArgumentException.

    Pattern letter 'X' (upper case) will output 'Z' when the offset to be output would be zero, whereas pattern letter 'x' (lower case) will output '+00', '+0000', or '+00:00'.

    Offset Z: This formats the offset based on the number of pattern letters.

    • One, two or three letters outputs the hour and minute, without a colon, such as '+0130'. The output will be '+0000' when the offset is zero.
    • Four letters outputs the full form of localized offset, equivalent to four letters of Offset-O. The output will be the corresponding localized offset text if the offset is zero.
    • Five letters outputs the hour, minute, with optional second if non-zero, with colon. It outputs 'Z' if the offset is zero.
    • Six or more letters throws IllegalArgumentException.

    As you can see, you used 1 Z, which means -0600.

    To parse a time zone with hours and minutes (optional seconds), with colons, you need one of the highlighted patterns:

    XXX      UTC is `Z`.
    XXXXX    UTC is `Z`. Optional seconds.
    xxx      UTC is `+00:00`
    xxxxx    UTC is `+00:00`. Optional seconds.
    ZZZZZ    UTC is `Z`. Optional seconds.