java.util.Date à XMLGregorianCalendar


601

N'existe-t-il pas un moyen pratique de passer d'un java.util.Date à un XMLGregorianCalendar?


FYI: Ces deux classes terribles ont été remplacées il y a des années par les classes java.time définies dans JSR 310. Voir la ZonedDateTimeclasse et de nouvelles méthodes de conversion ajoutées aux classes héritées. Détails dans cette réponse par Ole VV
Basil Bourque

Réponses:


36

Je voudrais prendre du recul et un regard moderne sur cette question vieille de 10 ans. Les classes mentionnées Dateet XMLGregorianCalendarsont désormais anciennes. Je conteste leur utilisation et propose des alternatives.

  • Datea toujours été mal conçu et a plus de 20 ans. C'est simple: ne l'utilisez pas.
  • XMLGregorianCalendarest vieux aussi et a un design à l'ancienne. Si je comprends bien, il a été utilisé pour produire des dates et des heures au format XML pour les documents XML. Comme 2009-05-07T19:05:45.678+02:00ou 2009-05-07T17:05:45.678Z. Ces formats concordent assez bien avec ISO 8601 pour que les classes de java.time, l'API moderne de date et d'heure Java, puissent les produire, ce que nous préférons.

Aucune conversion nécessaire

À de nombreuses fins (la plupart?), Le remplacement moderne d'un Datesera un Instant. An Instantest un point dans le temps (tout comme un Dateest).

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

Un exemple de sortie de cet extrait:

2009-05-07T17: 05: 45.678Z

C'est le même que le dernier de mes exemples de XMLGregorianCalendarchaînes ci-dessus. Comme la plupart d'entre vous le savent, cela vient du Instant.toStringfait d' être implicitement appelé par System.out.println. Avec java.time, dans de nombreux cas , nous ne devons pas les conversions dans les vieux jours que nous avons fait entre Date, Calendar, XMLGregorianCalendaret d' autres classes (dans certains cas , nous faisons des conversions de besoin, cependant, je vous montre un couple dans la section suivante) .

Contrôle du décalage

Ni a Dateni in Instantn'ont de fuseau horaire ni de décalage UTC. La réponse précédemment acceptée et toujours la plus votée par Ben Noland utilise le fuseau horaire par défaut actuel des JVM pour sélectionner le décalage du XMLGregorianCalendar. Pour inclure un décalage dans un objet moderne, nous utilisons un OffsetDateTime. Par exemple:

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

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

Encore une fois, cela est conforme au format XML. Si vous souhaitez réutiliser le paramètre de fuseau horaire JVM actuel, définissez zonesur ZoneId.systemDefault().

Et si j'ai absolument besoin d'un XMLGregorianCalendar?

Il existe plusieurs façons de convertir Instanten XMLGregorianCalendar. J'en présenterai un couple, chacun avec ses avantages et ses inconvénients. Tout d'abord, tout comme un XMLGregorianCalendarproduit une chaîne comme 2009-05-07T17:05:45.678Z, il peut également être construit à partir d'une telle chaîne:

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

2009-05-07T17: 05: 45.678Z

Pro: c'est court et je ne pense pas que ça donne de surprises. Inconvénient: Pour moi, cela ressemble à un gaspillage formatant l'instant en une chaîne et l'analysant en retour.

    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: C'est la conversion officielle. Le contrôle du décalage vient naturellement. Inconvénient: il passe par plusieurs étapes et est donc plus long.

Et si on avait un rendez-vous?

Si vous avez obtenu un Dateobjet à l' ancienne d'une API héritée que vous ne pouvez pas vous permettre de changer pour l'instant, convertissez-le en Instant:

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

La sortie est la même qu'avant:

2009-05-07T17: 05: 45.678Z

Si vous souhaitez contrôler le décalage, convertissez-le en un OffsetDateTimede la même manière que ci-dessus.

Si vous avez un ancien Dateet avez absolument besoin d'un ancien XMLGregorianCalendar, utilisez simplement la réponse de Ben Noland.

Liens


1034
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);

5
Est-il possible de conserver getInstance () en tant que variable statique dans une classe de convertisseur? J'ai essayé de le rechercher dans le JavaDoc mais je n'ai rien trouvé. Difficile de savoir s'il y aura des problèmes d'utilisation simultanée?
Martin

36
Si vous souhaitez utiliser JodaTime, vous pouvez le faire sur une seule ligne: DatatypeFactory.newInstance (). NewXMLGregorianCalendar (new DateTime (). ToGregorianCalendar ())
Nicolas Mommaerts

3
XMLGregorianCalendar date2 = DatatypeFactory.newInstance (). NewXMLGregorianCalendar (nouveau GregorianCalendar (YYYY, MM, DD));
Junchen Liu

3
Veuillez noter que Calendar n'est pas threadsafe et donc GregorianCalender ne l'est pas non plus. Voir aussi stackoverflow.com/questions/12131324/…
questionnaire

Version à une ligne - DatatypeFactory.newInstance (). NewXMLGregorianCalendar (new GregorianCalendar () {{setTime (yourDate);}})
Alex Vayda

205

Pour ceux qui pourraient se retrouver ici à la recherche de la conversion opposée (de XMLGregorianCalendarà Date):

XMLGregorianCalendar xcal = <assume this is initialized>;
java.util.Date dt = xcal.toGregorianCalendar().getTime();

31

Voici une méthode de conversion d'un GregorianCalendar en XMLGregorianCalendar; Je vais laisser la partie de la conversion d'un java.util.Date à GregorianCalendar comme un exercice pour vous:

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 :-)


6
C'est une solution pour convertir GregorianCalendar en XMLGregorianCalendar et non ce qui est indiqué dans la question
ftrujillo


12

Je pensais simplement ajouter ma solution ci-dessous, car les réponses ci-dessus ne répondaient pas exactement à mes besoins. Mon schéma Xml nécessitait des éléments de date et d'heure séparés, pas un champ DateTime unique. Le constructeur XMLGregorianCalendar standard utilisé ci-dessus générera un champ DateTime

Notez-y quelques gothca, comme devoir en ajouter un au mois (car java compte des mois à partir de 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);

10

J'espère que mon encodage ici est correct; D Pour le rendre plus rapide, il suffit d'utiliser l'appel laid getInstance () de GregorianCalendar au lieu de l'appel du constructeur:

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);
   }

}

14
-1 pour utiliser .getInstance (). GregorianCalendar.getInstance()est l'équivalent de Calendar.getInstance(). Le Calendar.getInstance()ne peut pas le rendre plus rapide, car il utilise le même new GregorianCalendar(), mais avant de vérifier également les paramètres régionaux par défaut et pourrait créer un calendrier japonais ou bouddish à la place, donc pour certains utilisateurs chanceux, ce sera le cas ClassCastException!
kan

6

En supposant que vous JAXBdécodez ou encodez du XML et que vous l'utilisez , il est alors possible de remplacer entièrement la liaison dateTime et d'utiliser autre chose que `XMLGregorianCalendar 'pour chaque date du schéma.

De cette façon, vous pouvez avoir JAXB faire des choses répétitives pendant que vous pouvez passer du temps à écrire du code génial qui offre de la valeur.

Exemple pour un jodatime DateTime: (Faire cela avec java.util.Date fonctionnerait également - mais avec certaines limitations. Je préfère le jodatime et il est copié à partir de mon code, donc je sais que cela fonctionne ...)

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

Et le convertisseur:

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);
    }
}

Voir ici: comment remplacer XmlGregorianCalendar par Date?

Si vous êtes heureux de simplement mapper à un instant basé sur le fuseau horaire + horodatage et que le fuseau horaire d'origine n'est pas vraiment pertinent, alors java.util.Datec'est probablement bien aussi.


0

Découvrez ce 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);

Vous pouvez voir l'exemple complet ici


Je ne pense pas que cette réponse n'apporte rien de nouveau. Vous pouvez peut-être modifier la réponse précédente au lieu d'en poster une autre presque la même.
hiver

1
Comment faire un format de date pour XMLGregorianCalendar?
Panadol Chong
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.