date changed when converting it from java.util.Date to javax.xml.datatype.XMLGregorianCalendar

431 Views Asked by At

the Date Thu Sep 27 00:00:00 CEST 2018

becomes

2018-09-26T22:00:00.000Z

when converted in XMLGregorianCalendar

by this method:

 public static XMLGregorianCalendar dateToXMLGregorianCalendar(Date date) throws DatatypeConfigurationException{
    GregorianCalendar cal = new GregorianCalendar();
    cal.setTime(date);
    return DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
}

How can I avoid this date change?

Tnx

2

There are 2 best solutions below

0
On

It’s a question with a number of possible answers depending on your circumstances and exact requirements. I am assuming that you are asking for an XMLGregorianCalendar because you are going to use it in an XML document where its toXMLFormat method produces the syntax you need.

Try if a LocalDate works

    LocalDate ld = LocalDate.of(2018, Month.SEPTEMBER, 27);
    System.out.println(ld);

This outputs:

2018-09-27

If what you need to put into your XML document is a date, not a date and time and UTC offset, this would be the logical solution. The above is a valid date format in XML (check the links at the bottom). Whether the receiver of your XML document accepts it I cannot tell. I’d find out if that were me.

The method in your question accepts a Date argument. The Date class is long outdated and has design problems, so avoid it if you can. If you cannot avoid it, convert it to LocalDate like this:

    ZoneId zone = ZoneId.of("Europe/Rome");
    LocalDate ld = date.toInstant().atZone(zone).toLocalDate();

Please use your desired time zone where I put Europe/Rome since it is never the same date in all time zones. The correct time zone is what controls whether you get September 26 or 27.

Use OffsetDateTime

    ZoneId zone = ZoneId.of("Europe/Rome");
    OffsetDateTime odt = LocalDate.of(2018, Month.SEPTEMBER, 27)
                            .atStartOfDay(zone)
                            .toOffsetDateTime();
    System.out.println(odt);

2018-09-27T00:00+02:00

This is almost the syntax you also get from XMLGregorianCalendar (XMLGregorianCalendar could produce it too if you wanted). Seconds and milliseconds are not included. Again, check if it’s OK. If it isn’t, format your OffsetDateTime into a String for your XML:

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxxx");
    String dateTimeString = odt.format(formatter);
    System.out.println(dateTimeString);

2018-09-27T00:00:00.000+02:00

This follows the syntax you got from XMLGregorianCalendar in your question exactly, only the date and time have not been changed. Again if you cannot avoid accepting an old-fashioned Date, convert:

    OffsetDateTime odt = date.toInstant().atZone(zone).toOffsetDateTime();

If you do need an XMLGregorianCalendar

    ZoneId zone = ZoneId.of("Europe/Rome");
    ZonedDateTime zdt = date.toInstant().atZone(zone);
    GregorianCalendar cal = GregorianCalendar.from(zdt);
    XMLGregorianCalendar xmlgcal = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
    System.out.println(xmlgcal);

2018-09-27T00:00:00.000+02:00

The specification of time zone controls the offset and thereby also the date and time produced.

Links

0
On

That is the same date & time.

Your first date is in timezone CEST, which is equivalent to UTC+2 Your second timestamp is rendered in Z timezone, which is equivalent to UTC+0

Thus, both mean the same point in time, but just render differently.

GregorianCalendar has a method to change the calendars timezone, if you want output in CEST date & time then I suggest you change the calendar timezone to that. See GregorianCalendar.setTimeZone for API reference.

It also kind of depends on how you retrieve your date from that calendar. If you just plan to use the .getTime() method that returns a plain Java Date object, then you can send this through a DateTimeFormatter to output the date in whatever timezone you desire.

If you only care about the actual "date" part of the date, and don't want to adapt it to various timezones, have a look at LocalDate instead.