651

Isn't there a convenient way of getting from a java.util.Date to a XMLGregorianCalendar?

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
mac
  • 9,885
  • 4
  • 36
  • 51
  • 2
    FYI: Both of these terrible classes were supplanted years ago by the *java.time* classes defined in JSR 310. See `ZonedDateTime` class, and new conversion methods added to the legacy classes. Details in [this Answer](https://stackoverflow.com/a/56313273/642706) by Ole V.V. – Basil Bourque May 26 '19 at 14:11

10 Answers10

1080
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
Ben Noland
  • 34,230
  • 18
  • 50
  • 51
  • 5
    Is it save to keep the getInstance() as a static variable in some converter class? I tried to look it up in the JavaDoc but couldn't find anything. Kinda hard to know if there will be problems in concurrent usage? – Martin Feb 11 '13 at 12:48
  • 38
    If you are willing to use JodaTime you can do this in one line: DatatypeFactory.newInstance().newXMLGregorianCalendar(new DateTime().toGregorianCalendar()) – Nicolas Mommaerts Mar 15 '13 at 14:19
  • 4
    XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar(YYYY, MM, DD)); – Junchen Liu Feb 19 '15 at 11:10
  • 3
    Please be aware of that Calendar isn't threadsafe and therefore also GregorianCalender isn't. See also http://stackoverflow.com/questions/12131324/is-java-util-calendar-thread-safe-or-not – questionaire Jun 03 '15 at 11:38
  • One line version - DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar() {{ setTime(yourDate); }}) – Alex Vayda Jun 27 '16 at 09:55
  • How to do a dateFormat for XMLGregorianCalendar? – Panadol Chong Jun 22 '18 at 03:10
  • @AlexVayda Avoid [double brace initialization](https://www.baeldung.com/java-double-brace-initialization) – Ole V.V. May 26 '19 at 08:04
  • FYI, the terribly troublesome date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `XMLGregorianCalendar` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque May 26 '19 at 14:13
  • @BasilBourque the link about making java.util.* legacy is pointing to wikipedia, was it intended? How exactly does it apply to JAXB which steel seems to require XMLGregorianCalendar? – 9ilsdx 9rvj 0lo Jun 06 '19 at 13:00
  • @9ilsdx9rvj0lo Re: Wikipedia, yes, intended, to explain an idiom peculiar to computing. Re: Using *java.time* with JAXB, see [this Answer](https://stackoverflow.com/a/24251661/642706) with a link to GitHub for [an implementation of an adapter](https://github.com/migesok/jaxb-java-time-adapters). – Basil Bourque Jun 06 '19 at 14:43
  • @BasilBourque Thanks for link. The issue still opened, it doesn't look like those classes will become real legacy soon... as much as we would wish it... – 9ilsdx 9rvj 0lo Jun 06 '19 at 14:46
  • @9ilsdx9rvj0lo Also, the alternatives to JAXB also have adapters to support *java.time*, such as Jackson and GSON. – Basil Bourque Jun 06 '19 at 14:51
209

For those that might end up here looking for the opposite conversion (from XMLGregorianCalendar to Date):

XMLGregorianCalendar xcal = <assume this is initialized>;
java.util.Date dt = xcal.toGregorianCalendar().getTime();
jstricker
  • 2,132
  • 1
  • 30
  • 44
Nuno Furtado
  • 4,548
  • 8
  • 37
  • 57
68

I should like to take a step back and a modern look at this 10 years old question. The classes mentioned, Date and XMLGregorianCalendar, are old now. I challenge the use of them and offer alternatives.

  • Date was always poorly designed and is more than 20 years old. This is simple: don’t use it.
  • XMLGregorianCalendar is old too and has an old-fashioned design. As I understand it, it was used for producing dates and times in XML format for XML documents. Like 2009-05-07T19:05:45.678+02:00 or 2009-05-07T17:05:45.678Z. These formats agree well enough with ISO 8601 that the classes of java.time, the modern Java date and time API, can produce them, which we prefer.

No conversion necessary

For many (most?) purposes the modern replacement for a Date will be an Instant. An Instant is a point in time (just as a Date is).

    Instant yourInstant = // ...
    System.out.println(yourInstant);

An example output from this snippet:

2009-05-07T17:05:45.678Z

It’s the same as the latter of my example XMLGregorianCalendar strings above. As most of you know, it comes from Instant.toString being implicitly called by System.out.println. With java.time, in many cases we don’t need the conversions that in the old days we made between Date, Calendar, XMLGregorianCalendar and other classes (in some cases we do need conversions, though, I am showing you a couple in the next section).

Controlling the offset

Neither a Date nor in Instant has got a time zone nor a UTC offset. The previously accepted and still highest voted answer by Ben Noland uses the JVMs current default time zone for selecting the offset of the XMLGregorianCalendar. To include an offset in a modern object we use an OffsetDateTime. For example:

    ZoneId zone = ZoneId.of("America/Asuncion");
    OffsetDateTime dateTime = yourInstant.atZone(zone).toOffsetDateTime();
    System.out.println(dateTime);

2009-05-07T13:05:45.678-04:00

Again this conforms with XML format. If you want to use the current JVM time zone setting again, set zone to ZoneId.systemDefault().

What if I absolutely need an XMLGregorianCalendar?

There are more ways to convert Instant to XMLGregorianCalendar. I will present a couple, each with its pros and cons. First, just as an XMLGregorianCalendar produces a string like 2009-05-07T17:05:45.678Z, it can also be built from such a string:

    String dateTimeString = yourInstant.toString();
    XMLGregorianCalendar date2
            = DatatypeFactory.newInstance().newXMLGregorianCalendar(dateTimeString);
    System.out.println(date2);

2009-05-07T17:05:45.678Z

Pro: it’s short and I don’t think it gives any surprises. Con: To me it feels like a waste formatting the instant into a string and parsing it back.

    ZonedDateTime dateTime = yourInstant.atZone(zone);
    GregorianCalendar c = GregorianCalendar.from(dateTime);
    XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
    System.out.println(date2);

2009-05-07T13:05:45.678-04:00

Pro: It’s the official conversion. Controlling the offset comes naturally. Con: It goes through more steps and is therefore longer.

What if we got a Date?

If you got an old-fashioned Date object from a legacy API that you cannot afford to change just now, convert it to Instant:

    Instant i = yourDate.toInstant();
    System.out.println(i);

Output is the same as before:

2009-05-07T17:05:45.678Z

If you want to control the offset, convert further to an OffsetDateTime in the same way as above.

If you’ve got an old-fashioned Date and absolutely need an old-fashioned XMLGregorianCalendar, just use the answer by Ben Noland.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 7
    Your answer is not really answer to the original question. Its fine and fun when you can choose between legacy and modern code. But if you come here with this question its not like you have the choice. Even your sample to convert is plain wrong, since it doesn't work in java 7 and below. – Nagh Oct 14 '20 at 17:34
  • 2
    Thank you, @Nagh, for the criticism, appreciated. I admit I had estimated that most users would have the choice. For those (many or few) whose evil boss forces them to use Java 7, I recommend using java.time through the backport, [ThreeTen Backport](https://www.threeten.org/threetenbp/). You may of course also look at the many other answers. I still consider code that uses a feature from Java 8 or later correct, or most of the code I write in my work is plain wrong. You are correct: I believe more in writing *helpful* answer (at least to some) than *direct* answers to the questions as asked. – Ole V.V. Oct 14 '20 at 17:44
  • 2
    _I believe more in writing helpful answer (at least to some) than direct answers_ I would agree on that, however helpful answer must include direct answer to be really helpful. I still have to deal with Java 5 code, so feel my pain. – Nagh Oct 14 '20 at 18:00
  • I feel your pain, @Nagh. If you have the choice, you may look into [Joda-Time](https://www.joda.org/joda-time/) for any serious date and time work, it too produces ISO 8601 out of the box. When writing this answer one and a half years ago I saw no point in repeating the direct answer that many others had already given. Had it been missing, I agree, then I would have included it. – Ole V.V. Oct 14 '20 at 18:11
  • Date is still being used a lot. – Enerccio May 16 '21 at 05:23
  • @Enerccio Unfortunately you are correct. Thanks for confirming that I am not beating a dead horse when I recommend against it. – Ole V.V. May 17 '21 at 05:01
  • @OleV.V. yes but your "answer" does not actually answer when someone needs Date->XML calendar unlike answer below. – Enerccio May 17 '21 at 08:38
32

Here is a method for converting from a GregorianCalendar to XMLGregorianCalendar; I'll leave the part of converting from a java.util.Date to GregorianCalendar as an exercise for you:

import java.util.GregorianCalendar;

import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

public class DateTest {

   public static void main(final String[] args) throws Exception {
      GregorianCalendar gcal = new GregorianCalendar();
      XMLGregorianCalendar xgcal = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar(gcal);
      System.out.println(xgcal);
   }

}

EDIT: Slooow :-)

sasuke
  • 6,589
  • 5
  • 36
  • 35
  • 7
    This a solution to convert GregorianCalendar to XMLGregorianCalendar and not what is indicated in the question – ftrujillo Jan 21 '15 at 15:25
23

A one line example using Joda-Time library:

XMLGregorianCalendar xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(new DateTime().toGregorianCalendar());

Credit to Nicolas Mommaerts from his comment in the accepted answer.

Community
  • 1
  • 1
Chris Knight
  • 24,333
  • 24
  • 88
  • 134
12

Just thought I'd add my solution below, since the answers above did not meet my exact needs. My Xml schema required seperate Date and Time elements, not a singe DateTime field. The standard XMLGregorianCalendar constructor used above will generate a DateTime field

Note there a couple of gothca's, such as having to add one to the month (since java counts months from 0).

GregorianCalendar cal = new GregorianCalendar();
cal.setTime(yourDate);
XMLGregorianCalendar xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendarDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH), 0);
XMLGregorianCalendar xmlTime = DatatypeFactory.newInstance().newXMLGregorianCalendarTime(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND), 0);
Community
  • 1
  • 1
khylo
  • 4,430
  • 3
  • 29
  • 24
10

I hope my encoding here is right ;D To make it faster just use the ugly getInstance() call of GregorianCalendar instead of constructor call:

import java.util.GregorianCalendar;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

public class DateTest {

   public static void main(final String[] args) throws Exception {
      // do not forget the type cast :/
      GregorianCalendar gcal = (GregorianCalendar) GregorianCalendar.getInstance();
      XMLGregorianCalendar xgcal = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar(gcal);
      System.out.println(xgcal);
   }

}
Jean-François Savard
  • 20,626
  • 7
  • 49
  • 76
Daniel K.
  • 109
  • 1
  • 2
  • 14
    -1 for using .getInstance(). `GregorianCalendar.getInstance()` is the equivalent of `Calendar.getInstance()`. The `Calendar.getInstance()` cannot make it faster, because it uses the same `new GregorianCalendar()`, but before it also checks the default locale and could create Japanese or Buddish calendar instead, so for some lucky users it will be `ClassCastException`! – kan Apr 19 '12 at 09:39
8

Assuming you are decoding or encoding xml and using JAXB, then it's possible to replace the dateTime binding entirely and use something else than `XMLGregorianCalendar' for every date in the schema.

In that way you can have JAXB do the repetitive stuff while you can spend the time on writing awesome code that delivers value.

Example for a jodatime DateTime: (Doing this with java.util.Date would also work - but with certain limitations. I prefer jodatime and it's copied from my code so I know it works...)

<jxb:globalBindings>
    <jxb:javaType name="org.joda.time.LocalDateTime" xmlType="xs:dateTime"
        parseMethod="test.util.JaxbConverter.parseDateTime"
        printMethod="se.seb.bis.test.util.JaxbConverter.printDateTime" />
    <jxb:javaType name="org.joda.time.LocalDate" xmlType="xs:date"
        parseMethod="test.util.JaxbConverter.parseDate"
        printMethod="test.util.JaxbConverter.printDate" />
    <jxb:javaType name="org.joda.time.LocalTime" xmlType="xs:time"
        parseMethod="test.util.JaxbConverter.parseTime"
        printMethod="test.util.JaxbConverter.printTime" />
    <jxb:serializable uid="2" />
</jxb:globalBindings>

And the converter:

public class JaxbConverter {
static final DateTimeFormatter dtf = ISODateTimeFormat.dateTimeNoMillis();
static final DateTimeFormatter df = ISODateTimeFormat.date();
static final DateTimeFormatter tf = ISODateTimeFormat.time();

public static LocalDateTime parseDateTime(String s) {
    try {
        if (StringUtils.trimToEmpty(s).isEmpty())
            return null;
        LocalDateTime r = dtf.parseLocalDateTime(s);
        return r;
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

public static String printDateTime(LocalDateTime d) {
    try {
        if (d == null)
            return null;
        return dtf.print(d);
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

public static LocalDate parseDate(String s) {
    try {
        if (StringUtils.trimToEmpty(s).isEmpty())
            return null;
        return df.parseLocalDate(s);
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

public static String printDate(LocalDate d) {
    try {
        if (d == null)
            return null;
        return df.print(d);
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

public static String printTime(LocalTime d) {
    try {
        if (d == null)
            return null;
        return tf.print(d);
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

public static LocalTime parseTime(String s) {
    try {
        if (StringUtils.trimToEmpty(s).isEmpty())
            return null;
        return df.parseLocalTime(s);
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

See here: how replace XmlGregorianCalendar by Date?

If you are happy to just map to an instant based on the timezone+timestamp, and the original timezone is not really relevant, then java.util.Date is probably fine too.

Community
  • 1
  • 1
KarlP
  • 5,149
  • 2
  • 28
  • 41
2

Check out this code :-

/* Create Date Object */
Date date = new Date();
XMLGregorianCalendar xmlDate = null;
GregorianCalendar gc = new GregorianCalendar();

gc.setTime(date);

try{
    xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
}
catch(Exception e){
    e.printStackTrace();
}

System.out.println("XMLGregorianCalendar :- " + xmlDate);

You can see complete example here

pringi
  • 3,987
  • 5
  • 35
  • 45
Akash
  • 39
  • 2
-1

My solution

public static XMLGregorianCalendar DateToXMLGregorianCalendar(Date date) {

    GregorianCalendar gregoriancalendar = new GregorianCalendar();
    gregoriancalendar.setTime(date);
    XMLGregorianCalendar xmlGregorianCalendar = new XMLGregorianCalendarImpl(gregoriancalendar);
    return xmlGregorianCalendar;
}