java.util.Date in XMLGregorianCalendar


601

Non esiste un modo conveniente per passare da java.util.Date a XMLGregorianCalendar?


FYI: Entrambe queste terribili classi sono state soppiantate anni fa dalle classi java.time definite in JSR 310. Vedi ZonedDateTimeclasse e nuovi metodi di conversione aggiunti alle classi legacy. Dettagli in questa risposta di Ole VV
Basil Bourque

Risposte:


36

Vorrei fare un passo indietro e uno sguardo moderno a questa domanda di 10 anni. Le classi menzionate Datee XMLGregorianCalendarora sono vecchie. Sfido il loro utilizzo e offro alternative.

  • Dateè sempre stato progettato male e ha più di 20 anni. Questo è semplice: non usarlo.
  • XMLGregorianCalendarè troppo vecchio e ha un design vecchio stile. A quanto ho capito, è stato utilizzato per la produzione di date e orari in formato XML per documenti XML. Come 2009-05-07T19:05:45.678+02:00o 2009-05-07T17:05:45.678Z. Questi formati concordano abbastanza bene con ISO 8601 che le classi di java.time, la moderna API di data e ora di Java, possono produrli, che preferiamo.

Nessuna conversione necessaria

Per molti (la maggior parte?) Scopi il moderno sostituto di un Datesarà un Instant. An Instantè un punto nel tempo (così come Dateè).

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

Un esempio di output da questo frammento:

2009-05-07T17: 05: 45.678Z

È lo stesso di quest'ultimo delle XMLGregorianCalendarstringhe di esempio sopra. Come molti di voi sanno, deriva Instant.toStringdall'essere implicitamente chiamato da System.out.println. Con java.time, in molti casi, non abbiamo bisogno le conversioni che in passato abbiamo fatto tra il Date, Calendar, XMLGregorianCalendare altre classi (in alcuni casi che facciamo conversioni bisogno, però, mi sto mostrando una coppia nel prossimo paragrafo) .

Controllo dell'offset

Né un Datené in Instantha un fuso orario né un offset UTC. La risposta precedentemente accettata e ancora più votata da Ben Noland utilizza il fuso orario predefinito corrente di JVM per selezionare l'offset del XMLGregorianCalendar. Per includere un offset in un oggetto moderno usiamo un OffsetDateTime. Per esempio:

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

2009-05-07T13: 05: 45,678-04: 00

Ancora una volta questo è conforme al formato XML. Se si desidera utilizzare nuovamente l'impostazione corrente del fuso orario JVM, impostare zonesu ZoneId.systemDefault().

Cosa succede se ho assolutamente bisogno di un XMLGregorianCalendar?

Ci sono più modi per convertire Instanta XMLGregorianCalendar. Presenterò una coppia, ciascuno con i suoi pro e contro. Innanzitutto, proprio come XMLGregorianCalendarproduce una stringa simile 2009-05-07T17:05:45.678Z, può anche essere costruita da tale stringa:

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

2009-05-07T17: 05: 45.678Z

Pro: è breve e non credo che dia sorprese. Contro: Per me sembra uno spreco formattare l'istante in una stringa e analizzarlo indietro.

    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: è la conversione ufficiale. Il controllo dell'offset è naturale. Contro: passa attraverso più passaggi ed è quindi più lungo.

E se avessimo un appuntamento?

Se hai ottenuto un Dateoggetto vecchio stile da un'API legacy che non puoi permetterti di cambiare in questo momento, convertilo in Instant:

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

L'output è lo stesso di prima:

2009-05-07T17: 05: 45.678Z

Se si desidera controllare l'offset, convertire ulteriormente in un OffsetDateTimecome sopra.

Se hai un vecchio stile Datee hai assolutamente bisogno di un vecchio stile XMLGregorianCalendar, usa la risposta di Ben Noland.

link


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

5
È possibile salvare getInstance () come variabile statica in alcune classi di convertitori? Ho provato a cercarlo in JavaDoc ma non sono riuscito a trovare nulla. Difficile sapere se ci saranno problemi nell'uso simultaneo?
Martin,

36
Se sei disposto a utilizzare JodaTime puoi farlo in una riga: DatatypeFactory.newInstance (). NewXMLGregorianCalendar (new DateTime (). ToGregorianCalendar ())
Nicolas Mommaerts

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

3
Tieni presente che Calendar non è sicuro per i thread e quindi anche GregorianCalender. Vedi anche stackoverflow.com/questions/12131324/…
questionaire

Versione a una riga - DatatypeFactory.newInstance (). NewXMLGregorianCalendar (new GregorianCalendar () {{setTime (yourDate);}})
Alex Vayda,

205

Per quelli che potrebbero finire qui alla ricerca della conversione opposta (da XMLGregorianCalendara Date):

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

31

Ecco un metodo per la conversione da un GregorianCalendar a XMLGregorianCalendar; Lascerò la parte della conversione da java.util.Date a GregorianCalendar come esercizio per te:

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
Questa è una soluzione per convertire GregorianCalendar in XMLGregorianCalendar e non ciò che è indicato nella domanda
ftrujillo


12

Ho pensato di aggiungere la mia soluzione di seguito, poiché le risposte di cui sopra non hanno soddisfatto le mie esatte esigenze. Il mio schema Xml richiedeva elementi separati di data e ora, non un singolo campo DateTime. Il costruttore XMLGregorianCalendar standard usato sopra genererà un campo DateTime

Nota che ci sono un paio di gothca, come doverne aggiungere uno al mese (poiché java conta mesi da 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

Spero che la mia codifica qui sia corretta; D Per renderlo più veloce basta usare la brutta chiamata getInstance () di GregorianCalendar invece della chiamata del costruttore:

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 per l'utilizzo di .getInstance (). GregorianCalendar.getInstance()è l'equivalente di Calendar.getInstance(). Non Calendar.getInstance()può renderlo più veloce, perché utilizza lo stesso new GregorianCalendar(), ma prima controlla anche le impostazioni internazionali predefinite e potrebbe invece creare un calendario giapponese o buddish, quindi per alcuni utenti fortunati lo sarà ClassCastException!
gennaio

6

Supponendo che tu stia decodificando o codificando xml e utilizzandolo JAXB, è possibile sostituire completamente l'associazione dateTime e utilizzare qualcosa di diverso da "XMLGregorianCalendar" per ogni data nello schema.

In questo modo puoi JAXBfare le cose ripetitive mentre puoi passare il tempo a scrivere codice fantastico che offra valore.

Esempio per un jodatime DateTime: (Anche fare questo con java.util.Date funzionerebbe, ma con alcune limitazioni. Preferisco jodatime ed è copiato dal mio codice, quindi so che funziona ...)

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

E il convertitore:

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

Vedi qui: come sostituire XmlGregorianCalendar per data?

Se sei felice di mappare solo un istante in base al fuso orario + timestamp e il fuso orario originale non è realmente pertinente, allora java.util.Dateprobabilmente va bene anche.


0

Dai un'occhiata a questo codice: -

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

Puoi vedere l'esempio completo qui


Non penso che questa risposta non fornisca nulla di nuovo .. Forse puoi modificare la risposta precedente invece di postarne un'altra quasi uguale.
inverno

1
Come fare un dateFormat per XMLGregorianCalendar?
Panadol Chong,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.