Réponses:
Je voudrais prendre du recul et un regard moderne sur cette question vieille de 10 ans. Les classes mentionnées Date
et XMLGregorianCalendar
sont désormais anciennes. Je conteste leur utilisation et propose des alternatives.
Date
a toujours été mal conçu et a plus de 20 ans. C'est simple: ne l'utilisez pas.XMLGregorianCalendar
est 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:00
ou 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.À de nombreuses fins (la plupart?), Le remplacement moderne d'un Date
sera un Instant
. An Instant
est un point dans le temps (tout comme un Date
est).
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 XMLGregorianCalendar
chaînes ci-dessus. Comme la plupart d'entre vous le savent, cela vient du Instant.toString
fait 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
, XMLGregorianCalendar
et d' autres classes (dans certains cas , nous faisons des conversions de besoin, cependant, je vous montre un couple dans la section suivante) .
Ni a Date
ni in Instant
n'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 zone
sur ZoneId.systemDefault()
.
Il existe plusieurs façons de convertir Instant
en XMLGregorianCalendar
. J'en présenterai un couple, chacun avec ses avantages et ses inconvénients. Tout d'abord, tout comme un XMLGregorianCalendar
produit 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.
Si vous avez obtenu un Date
objet à 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 OffsetDateTime
de la même manière que ci-dessus.
Si vous avez un ancien Date
et avez absolument besoin d'un ancien XMLGregorianCalendar
, utilisez simplement la réponse de Ben Noland.
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
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();
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 :-)
Un exemple d'une ligne utilisant la bibliothèque Joda-Time :
XMLGregorianCalendar xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(new DateTime().toGregorianCalendar());
Crédit à Nicolas Mommaerts de son commentaire dans la réponse acceptée .
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);
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);
}
}
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
!
En supposant que vous JAXB
dé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.Date
c'est probablement bien aussi.
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
ZonedDateTime
classe et de nouvelles méthodes de conversion ajoutées aux classes héritées. Détails dans cette réponse par Ole VV