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.