Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

xsd:dateTime to Java OffsetDateTime

In order to properly handle an xs:dateTime with JAXB, I have to write my own converter from String->java.time.OffsetDateTime.

As mentioned in the XML Schema Definition, dateTime was inspired by ISO 8601. I used OffsetDateTime.parse(s, DateTimeFormatter.ISO_OFFSET_DATE_TIME) to parse the xs:dateTime, which works fine for e.g.

"2007-12-03T10:15:30+01:00" //or
"2007-12-03T10:15:30Z"

Sadly, in xs:dateTime the offset part is declared optional, so parsing the valid

"2016-03-02T17:09:55"

throws an DateTimeParseException.

Is there a DateTimeFormatter for OffsetDateTime, which also handles unzoned xs:dateTimes (probably with a default timezone)?

like image 355
Stefan K. Avatar asked Mar 02 '16 18:03

Stefan K.


2 Answers

I don't think there's a built-in one but you can make your own with the help of the DateTimeFormatterBuilder class.

You can specify an optional offset enclosed in squared brackets, i.e. [XXXXX] (to match "+HH:MM:ss"), Then, you can provide a default offset (parseDefaulting) in the case where it is not present. If you want to default to UTC, you can set 0 to specify no offset; and if you want to default to the current offset of the VM, you can get it with OffsetDateTime.now().getLong(ChronoField.OFFSET_SECONDS).

public static void main(String[] args) {
    String[] dates = {
        "2007-12-03T10:15:30+01:00",
        "2007-12-03T10:15:30Z",
        "2016-03-02T17:09:55",
        "2016-03-02T17:09:55Z"
    };
    DateTimeFormatter formatter =
        new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd'T'HH:mm:ss[XXXXX]")
                                      .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
                                      // or OffsetDateTime.now().getLong(ChronoField.OFFSET_SECONDS)
                                      .toFormatter();
    for (String date : dates) {
        System.out.println(OffsetDateTime.parse(date, formatter));
    }
}
like image 147
Tunaki Avatar answered Nov 16 '22 09:11

Tunaki


just to show my current solution which resolves the unzoned format to the systems default offset at the currently in parse dateTime.

public static OffsetDateTime parseDateTime(String s) {
    if (s == null) {
        return null;
    }
    try {
        return OffsetDateTime.parse(s, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
    } catch (DateTimeParseException e) {
        try { // try to handle zoneless xml dateTime
            LocalDateTime localDateTime = LocalDateTime.parse(s, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            ZoneOffset offset = ZoneId.systemDefault().getRules().getOffset(localDateTime);
            return OffsetDateTime.of(localDateTime.toLocalDate(), localDateTime.toLocalTime(), offset);
        } catch (Exception fallbackTryException) {
            throw e;
        }
    }
}
like image 45
Stefan K. Avatar answered Nov 16 '22 09:11

Stefan K.