java.util.Date to XMLGregorianCalendar

601

¿No hay una manera conveniente de pasar de un java.util.Date a un XMLGregorianCalendar?

Mac
fuente
FYI: Ambas clases terribles fueron suplantadas hace años por las clases java.time definidas en JSR 310. Vea la ZonedDateTimeclase y los nuevos métodos de conversión agregados a las clases heredadas. Detalles en esta respuesta por Ole VV
Basil Bourque

Respuestas:

36

Me gustaría dar un paso atrás y una mirada moderna a esta pregunta de 10 años. Las clases mencionadas, Datey XMLGregorianCalendar, son viejas ahora. Desafío el uso de ellos y ofrezco alternativas.

  • Datesiempre fue mal diseñado y tiene más de 20 años. Esto es simple: no lo use.
  • XMLGregorianCalendares viejo también y tiene un diseño anticuado. Según tengo entendido, se utilizó para producir fechas y horas en formato XML para documentos XML. Me gusta 2009-05-07T19:05:45.678+02:00o 2009-05-07T17:05:45.678Z. Estos formatos concuerdan bastante bien con ISO 8601 que las clases de java.time, la API moderna de fecha y hora de Java, pueden producirlos, lo que preferimos.

No es necesaria conversión

Para muchos (¿la mayoría?), El reemplazo moderno de un Dateserá un Instant. Un Instantes un punto en el tiempo (tal como Datees).

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

Un ejemplo de salida de este fragmento:

2009-05-07T17: 05: 45.678Z

Es lo mismo que la última de mis XMLGregorianCalendarcadenas de ejemplo anteriores. Como la mayoría de ustedes saben, proviene de Instant.toStringser llamado implícitamente por System.out.println. Con java.time, en muchos casos no necesitamos las conversiones que en los viejos tiempos que hicimos entre Date, Calendar, XMLGregorianCalendary otras clases (en algunos casos que hacemos conversiones necesidad, sin embargo, estoy mostrando un par en la siguiente sección) .

Controlando el desplazamiento

Ni a Dateni in Instanttiene una zona horaria ni un desplazamiento UTC. La respuesta previamente aceptada y aún más votada por Ben Noland utiliza la zona horaria predeterminada actual de JVM para seleccionar el desplazamiento de la XMLGregorianCalendar. Para incluir un desplazamiento en un objeto moderno, usamos un OffsetDateTime. Por ejemplo:

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

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

Nuevamente, esto se ajusta al formato XML. Si desea volver a utilizar la configuración de zona horaria JVM actual, configure zoneen ZoneId.systemDefault().

¿Qué sucede si realmente necesito un XMLGregorianCalendar?

Hay más maneras de convertir Instanta XMLGregorianCalendar. Presentaré una pareja, cada una con sus ventajas y desventajas. Primero, así como un XMLGregorianCalendarproduce una cadena como 2009-05-07T17:05:45.678Z, también se puede construir a partir de dicha cadena:

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

2009-05-07T17: 05: 45.678Z

Pro: es breve y no creo que dé sorpresas. Con: Para mí, se siente como un desperdicio formatear el instante en una cadena y analizarlo nuevamente.

    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: es la conversión oficial. Controlar el desplazamiento es algo natural. Con: pasa por más pasos y, por lo tanto, es más largo.

¿Qué pasa si tenemos una cita?

Si obtuvo un Dateobjeto antiguo de una API heredada que no puede permitirse cambiar en este momento, conviértalo a Instant:

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

La salida es la misma que antes:

2009-05-07T17: 05: 45.678Z

Si desea controlar el desplazamiento, convierta más a OffsetDateTimea de la misma manera que arriba.

Si tienes un anticuado Datey necesitas un anticuado XMLGregorianCalendar, usa la respuesta de Ben Noland.

Enlaces

Ole VV
fuente
1034
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
Ben Noland
fuente
55
¿Es seguro mantener getInstance () como una variable estática en alguna clase de convertidor? Traté de buscarlo en JavaDoc pero no pude encontrar nada. ¿Es difícil saber si habrá problemas en el uso concurrente?
Martin
36
Si está dispuesto a usar JodaTime, puede hacerlo en una línea: DatatypeFactory.newInstance (). NewXMLGregorianCalendar (new DateTime (). ToGregorianCalendar ())
Nicolas Mommaerts
3
XMLGregorianCalendar date2 = DatatypeFactory.newInstance (). NewXMLGregorianCalendar (nuevo GregorianCalendar (AAAA, MM, DD));
Junchen Liu
3
Tenga en cuenta que Calendar no es seguro para subprocesos y, por lo tanto, tampoco GregorianCalender. Ver también stackoverflow.com/questions/12131324/…
cuestionario
Versión de una línea: DatatypeFactory.newInstance (). NewXMLGregorianCalendar (new GregorianCalendar () {{setTime (yourDate);}})
Alex Vayda
205

Para aquellos que podrían terminar aquí buscando la conversión opuesta (de XMLGregorianCalendara Date):

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

Aquí hay un método para convertir de un GregorianCalendar a XMLGregorianCalendar; Dejaré la parte de convertir de java.util.Date a GregorianCalendar como ejercicio para ti:

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

}

EDITAR: Slooow :-)

sasuke
fuente
66
Esta es una solución para convertir GregorianCalendar a XMLGregorianCalendar y no lo que se indica en la pregunta
ftrujillo
12

Solo pensé en agregar mi solución a continuación, ya que las respuestas anteriores no satisfacían mis necesidades exactas. Mi esquema Xml requería elementos separados de fecha y hora, no un solo campo de fecha y hora. El constructor estándar XMLGregorianCalendar utilizado anteriormente generará un campo DateTime

Tenga en cuenta que hay un par de gothca, como tener que agregar uno al mes (ya que Java cuenta meses desde 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);
khylo
fuente
10

Espero que mi codificación sea correcta; D Para hacerlo más rápido, simplemente use la llamada fea getInstance () de GregorianCalendar en lugar de la llamada del constructor:

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

}
Daniel K.
fuente
14
-1 para usar .getInstance (). GregorianCalendar.getInstance()es el equivalente de Calendar.getInstance(). No Calendar.getInstance()puede hacerlo más rápido, porque usa lo mismo new GregorianCalendar(), pero antes también comprueba la configuración regional predeterminada y podría crear un calendario japonés o budista, ¡así que para algunos usuarios afortunados lo será ClassCastException!
kan
6

Suponiendo que está decodificando o codificando xml y está utilizando JAXB, entonces es posible reemplazar el enlace dateTime por completo y usar algo más que 'XMLGregorianCalendar' para cada fecha en el esquema.

De esa manera, puede JAXBhacer las cosas repetitivas mientras puede pasar el tiempo escribiendo código increíble que brinde valor.

Ejemplo de jodatime DateTime: (Hacer esto con java.util.Date también funcionaría, pero con ciertas limitaciones. Prefiero jodatime y está copiado de mi código, así que sé que funciona ...)

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

Y el convertidor:

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

Vea aquí: ¿cómo reemplazar XmlGregorianCalendar por fecha?

Si está contento de mapear a un instante en función de la zona horaria + marca de tiempo, y la zona horaria original no es realmente relevante, entonces java.util.Dateprobablemente también esté bien.

KarlP
fuente
0

Mira este código: -

/* 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);

Puedes ver el ejemplo completo aquí

Akash
fuente
No creo que esta respuesta no proporcione nada nuevo. Quizás pueda editar la respuesta anterior en lugar de publicar otra casi igual.
invierno
1
¿Cómo hacer un dateFormat para XMLGregorianCalendar?
Panadol Chong