61

What's the best way to convert between LocalDate from Java 8 and XMLGregorianCalendar?

maja
  • 17,250
  • 17
  • 82
  • 125
  • It's similar to what have been answered here http://stackoverflow.com/questions/835889/java-util-date-to-xmlgregoriancalendar?answertab=votes#tab-top – Ankur Anand Apr 21 '15 at 10:03
  • 3
    @AnkurAnand I don't think that the question is very similar - I needed to convert from `LocalDate`, not `Date`, and I aksed for a convertion in both directions. The answers might be similar because the conversion requires `Date` as an in-between-step, but the question is not. – maja Apr 21 '15 at 14:08

4 Answers4

106

Converting from LocalDate to XMLGregorianCalendar:

LocalDate date = LocalDate.now();
GregorianCalendar gcal = GregorianCalendar.from(date.atStartOfDay(ZoneId.systemDefault()));
XMLGregorianCalendar xcal = DatatypeFactory.newInstance().newXMLGregorianCalendar(gcal);

Converting back is simpler:

xcal.toGregorianCalendar().toZonedDateTime().toLocalDate();
JodaStephen
  • 60,927
  • 15
  • 95
  • 117
  • 12
    When converting from LocalDate to XMLGregorianCalendar, avoid GregorianCalendar! The problem is that GregorianCalendar's timezone is a required field, but LocalDate has no timezone information in it! – riskop Jun 21 '16 at 14:19
  • Some dates with timezones will result in a fraction in the timezone value as a result of DayLight saving transition, for example `LocalDate.parse("1902-07-10").atStartOfDay(ZoneId.of("Asia/Riyadh"))` will result in `1902-07-10T00:00+03:06:52[Asia/Riyadh]` with timezone value `03:06:52` – Muhammad Hewedy Jun 13 '19 at 11:46
  • 3
    `xcal.toGregorianCalendar().toZonedDateTime().toLocalDate();` should be avoided as @MuhammadHewedy mentioned. There is problem with daylight saving and you can end with wrong dates. Better solution would be `LocalDateTime.parse(xcal.toString()).atOffset(OffsetDateTime.now().getOffset())` – bilak Jan 09 '20 at 13:02
17

The LocalDate stores only year/month/day information. There is no time nor time-zone information in it. The XMLGregorianCalendar stores date (year/month/day) + optionally time and optionally time zone information.

So converting from LocalDate to XMLGregorianCalendar is simple:

LocalDate in;
XMLGregorianCalendar out;
in = LocalDate.parse("1999-11-11");
out = DatatypeFactory.newInstance().newXMLGregorianCalendar(in.toString());

Converting from XMLGregorianCalendar to LocalDate might be not so simple, because XMLGregorianCalendar may have time and time-zone information which you simply can't store in LocalDate.

However, I guess that if you are converting from XMLGregorianCalendar to LocalDate then the XMLGregorianCalendar is resulting from a nontimezoned xsd:date element (represented as YYYY-MM-DD in the xml). In that case you should convert it like this:

XMLGregorianCalendar in;
LocalDate out;
in = DatatypeFactory.newInstance().newXMLGregorianCalendar("2011-11-11");
out = LocalDate.parse(in.toXMLFormat());

Whole example:

    {
        LocalDate in;
        XMLGregorianCalendar out;
        in = LocalDate.parse("1999-11-11");
        out = DatatypeFactory.newInstance().newXMLGregorianCalendar(in.toString());
        System.out.println("in: " + in.toString());
        System.out.println("out: " + out.toXMLFormat());
    }
    {
        XMLGregorianCalendar in;
        LocalDate out;
        in = DatatypeFactory.newInstance().newXMLGregorianCalendar("2011-11-11");
        out = LocalDate.parse(in.toXMLFormat());
        System.out.println("in: " + in.toXMLFormat());
        System.out.println("out: " + out.toString());
    }
riskop
  • 1,693
  • 1
  • 16
  • 34
6

To convert from LocalDate to XMLGregorianCalendar you can use

LocalDate localDate = ...;
GregorianCalendar calender = new GregorianCalendar();
Date utilDate = Date.from( localDate.atStartOfDay( ZoneId.systemDefault() ).toInstant() );
calender.setTime(utilDate);     
XMLGregorianCalendar xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(calender);

And to convert XMLGregorianCalendar back to LocalDate:

XMLGregorianCalendar xmlCal = ...;
Date utilDate = xmlCal.toGregorianCalendar().getTime();
LocalDate localDate = LocalDateTime.ofInstant( utilDate.toInstant(), ZoneId.systemDefault() ).toLocalDate();
maja
  • 17,250
  • 17
  • 82
  • 125
6

The following is a simple way to convert from LocalDate to XMLGregorianCalendar which both preserves the undefined fields (hours, timezone, etc.) and is efficient (i.e. no conversion to/from String). Unlike some of the other solutions this results in XML dates without timezones, e.g. <date>2018-11-06</date> instead of <date>2018-11-06+01:00</date>.

LocalDate date = ...;
XMLGregorianCalendar xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar();
xmlCal.setYear(date.getYear());
xmlCal.setMonth(date.getMonthValue());
xmlCal.setDay(date.getDayOfMonth());

Converting back is a bit simpler:

XMLGregorianCalendar xmlCal = ...
LocalDate date = LocalDate.of(xmlCal.getYear(), xmlCal.getMonth(), xmlCal.getDay());
Acanda
  • 672
  • 5
  • 12