Java 8 DateTime Format Date + Offset

Viewed 1601

I have to construct a XMLGregorianCalendar for a Webservice which expects a date in the format yyyy-MM-dd+01:00, where the value after + is derived from the time zone offsett.

So far I have experimented with:

DateTimeFormatter formatterDateWithOffset = DateTimeFormatter.ofPattern("yyyy-MM-ddZZ");

XMLGregorianCalendar xcal = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar(zonedDateTime.format(formatterDateWithOffset));

But this results in an IllegalArgumentExcpetion because the formatter produces 2017-09-29+0200

Is it possible to define a format string for the desired format?

3 Answers

If you have a look at the JavaDoc on DateTimeFormatter you'll see this:

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'. ... 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'.

Thus DateTimeFormatter formatterDateWithOffset = DateTimeFormatter.ofPattern("yyyy-MM-ddxxx"); should work.

In my comment I suggested using ZZZZ because the JavaDoc hinted at that as well but it will add the GMT part too (ZZZZZ seems to work even though the JavaDoc states: "Five letters outputs the hour, minute, with optional second if non-zero, with colon" ).

Instead of parsing you can create an instance of XMLGregorianCalendar passing to it year, month etc:

XMLGregorianCalendar xcal = DatatypeFactory.newInstance().newXMLGregorianCalendar(year, month....)

As @Thomas's answer said, one alternative is to use xxx (or XXX), as explained in javadoc. The only difference between those is when the offset is zero: XXX formats to Z, while xxx formats to +00:00:

Pattern  Count  Equivalent builder methods
-------  -----  --------------------------
XXX      3      appendOffset("+HH:MM","Z")
xxx      3      appendOffset("+HH:MM","+00:00")

Anyway, just choose one of them (I've tested with both, using a ZonedDateTime with ZoneOffset.UTC and both worked):

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-ddXXX");
String str = formatter.format(zonedDateTime);
XMLGregorianCalendar xcal = DatatypeFactory.newInstance().newXMLGregorianCalendar(str);

If you have a ZonedDateTime, it's easier to convert it to a GregorianCalendar, and then pass it to your DatatypeFactory:

ZonedDateTime zonedDateTime = ZonedDateTime.now();
GregorianCalendar cal = GregorianCalendar.from(zonedDateTime);
XMLGregorianCalendar xcal = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);

A tricky detail is that, when using the String pattern above (with only the date), the result will have the time fields (hour, minute, second and millisecond) set to zero, while converting to GregorianCalendar will use the time set in the ZonedDateTime.

But you can set the time to midnight before converting it to GregorianCalendar:

// convert to calendar (set the time to 00:00:00.000)
GregorianCalendar cal = GregorianCalendar.from(zonedDateTime.with(LocalTime.MIDNIGHT));

With this, the result will be the same as using the String.

Related