Correct java.time representation of XMLGregorianCalendar

200 Views Asked by At

I have a XML element with the following content:

<lastModified>2019-10-09T19:20:45.677+02:00</lastModified>

This is mapped to Java's XMLGregorianCalendar.

I need to convert this value in an appropriate java.time instance.

I am a little confused about which java.time class is the "correct" (i.e. lossless) representation of this XMLGregorianCalendar value.

I suppose it should be ZonedDateTime or is OffsetDateTime the better choice?

2

There are 2 best solutions below

3
On BEST ANSWER

The String you have ("2019-10-09T19:20:45.677+02:00") is in an ISO format that doesn't even need an extra formatter in order to parse it. The main reason for the use of an OffsetDateTime are the last 6 characters: +02:00, which denote an offset of 2 hours from UTC (more than just one time zone may actually have this offset at the same time).

You can convert this value into the proper java.time instance like this, for example:

public static void main(String[] args) throws DatatypeConfigurationException {
    // your example datetime
    String lastModified = "2019-10-09T19:20:45.677+02:00";
    // create an XMLGregorianCalendar for example purpose
    XMLGregorianCalendar xmlGC = DatatypeFactory.newInstance()
                                                .newXMLGregorianCalendar(lastModified);
    // print it once in order to see the values
    System.out.println("XMLGregorianCalendar: " + xmlGC.toString());
    // parse its toString() method to an OffsetDateTime
    OffsetDateTime lastModOdt = OffsetDateTime.parse(xmlGC.toString());
    // format the content of the OffsetDateTime in ISO standard
    System.out.println("OffsetDateTime:       " 
            + lastModOdt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
}

Output:

XMLGregorianCalendar: 2019-10-09T19:20:45.677+02:00
OffsetDateTime:       2019-10-09T19:20:45.677+02:00

This should be correct (lossless enough by losing no information).

0
On

I've been struggling with a similar problem all morning and Ole's comments were more insightful than the accepted answer so thought I should post the conclusion I came to.

Technically yes, the exact equivalent to XMLGregorianCalendar is OffsetDateTime (assuming your example, where you have y-m-d h:m:s+z fields populated) as the time zone offset is known but which actual time zone it is is unknown (as per other comments, there are many time zones all with offset +2:00). You can convert it easily like so, without going via an intermediary string:

xmlGC.toGregorianCalendar ().toZonedDateTime ().toOffsetDateTime ()

But I think the real answer is it depends what you want to do with it. In my case, I want to display the date/time to the user. If that is true, do you really care what time zone the date/time happened to be stored as in the XML? The following are both effectively identical, i.e. they both represent the same point in time.

<lastModified>2019-10-09T19:20:45.677+02:00</lastModified>
<lastModified>2019-10-09T20:20:45.677+01:00</lastModified>

If you don't care about the time zone from the XML and just the point in time it reperesents, then the correct answer is Instant, which you can get like

xmlGC.toGregorianCalendar ().toInstant ()

and from there apply whatever time zone the user is in, rather than the time zone from the XML. So for me the right answer was to do:

xmlGC.toGregorianCalendar ().toInstant ().atZone (ZoneId.systemDefault ())