java.util.Date to XMLGregorianCalendar

601

Gibt es nicht eine bequeme Möglichkeit, von einem java.util.Date zu einem XMLGregorianCalendar zu gelangen?

Mac
quelle
Zu Ihrer Information : Diese beiden schrecklichen Klassen wurden vor Jahren durch die in JSR 310 definierten java.time- Klassen ersetzt. Siehe ZonedDateTimeKlasse und neue Konvertierungsmethoden, die den Legacy-Klassen hinzugefügt wurden. Details in dieser Antwort von Ole VV
Basil Bourque

Antworten:

36

Ich möchte einen Schritt zurücktreten und einen modernen Blick auf diese 10 Jahre alte Frage werfen. Die erwähnten Klassen Dateund XMLGregorianCalendarsind jetzt alt. Ich fordere deren Verwendung heraus und biete Alternativen an.

  • Datewar immer schlecht gestaltet und ist mehr als 20 Jahre alt. Das ist einfach: benutze es nicht.
  • XMLGregorianCalendarist auch alt und hat ein altmodisches Design. Soweit ich weiß, wurde es zum Erstellen von Datums- und Uhrzeitangaben im XML-Format für XML-Dokumente verwendet. Wie 2009-05-07T19:05:45.678+02:00oder 2009-05-07T17:05:45.678Z. Diese Formate stimmen gut genug mit ISO 8601 überein, dass die Klassen von java.time, der modernen Java-API für Datum und Uhrzeit, sie erzeugen können, was wir bevorzugen.

Keine Konvertierung notwendig

Für viele (die meisten?) Zwecke wird der moderne Ersatz für a Dateein Instant. An Instantist ein Zeitpunkt (so wie a Dateist).

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

Eine Beispielausgabe dieses Snippets:

2009-05-07T17: 05: 45.678Z

Es ist dasselbe wie das letztere meiner XMLGregorianCalendarobigen Beispielzeichenfolgen . Wie die meisten von Ihnen wissen, kommt es davon, Instant.toStringdass sie implizit von angerufen werden System.out.println. Mit java.time in vielen Fällen brauchen wir nicht die Umsetzungen , die in den alten Tagen , die wir gemacht zwischen Date, Calendar, XMLGregorianCalendarund anderen Klassen (in einigen Fällen wir müssen Conversions tun, obwohl, zeige ich Ihnen ein paar im nächsten Abschnitt) .

Offset steuern

Weder a Datenoch in Instanthaben eine Zeitzone oder einen UTC-Offset. Die zuvor akzeptierte und immer noch am höchsten bewertete Antwort von Ben Noland verwendet die aktuelle Standardzeitzone der JVM zur Auswahl des Versatzes der XMLGregorianCalendar. Um einen Versatz in ein modernes Objekt aufzunehmen, verwenden wir ein OffsetDateTime. Zum Beispiel:

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

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

Auch dies entspricht dem XML-Format. Wenn Sie die aktuelle JVM-Zeitzoneneinstellung erneut verwenden möchten, setzen Sie zoneauf ZoneId.systemDefault().

Was ist, wenn ich unbedingt einen XMLGregorianCalendar benötige?

Es gibt mehr Möglichkeiten , konvertieren Instantzu XMLGregorianCalendar. Ich werde ein Paar vorstellen, jedes mit seinen Vor- und Nachteilen. Erstens kann XMLGregorianCalendarein String, wie er erzeugt 2009-05-07T17:05:45.678Z, auch aus einem solchen String erstellt werden:

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

2009-05-07T17: 05: 45.678Z

Pro: Es ist kurz und ich glaube nicht, dass es irgendwelche Überraschungen gibt. Con: Für mich fühlt es sich wie eine Verschwendung an, den Augenblick in einen String zu formatieren und ihn zurück zu analysieren.

    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 ist die offizielle Konvertierung. Die Steuerung des Offsets ist selbstverständlich. Con: Es geht durch mehr Schritte und ist daher länger.

Was ist, wenn wir ein Date haben?

Wenn Sie ein altmodisches DateObjekt von einer Legacy-API erhalten haben, dessen Änderung Sie sich gerade nicht leisten können, konvertieren Sie es in Instant:

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

Die Ausgabe ist dieselbe wie zuvor:

2009-05-07T17: 05: 45.678Z

Wenn Sie den Versatz steuern möchten, konvertieren Sie auf OffsetDateTimedie gleiche Weise wie oben weiter in a.

Wenn Sie eine altmodische haben Dateund unbedingt eine altmodische brauchen XMLGregorianCalendar, verwenden Sie einfach die Antwort von Ben Noland.

Links

Ole VV
quelle
1034
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
Ben Noland
quelle
5
Ist es sicher, getInstance () als statische Variable in einer Konverterklasse beizubehalten? Ich habe versucht, es im JavaDoc nachzuschlagen, konnte aber nichts finden. Etwas schwer zu wissen, ob es Probleme bei der gleichzeitigen Verwendung gibt?
Martin
36
Wenn Sie bereit sind, JodaTime zu verwenden, können Sie dies in einer Zeile tun: DatatypeFactory.newInstance (). NewXMLGregorianCalendar (new DateTime (). ToGregorianCalendar ())
Nicolas Mommaerts
3
XMLGregorianCalendar date2 = DatatypeFactory.newInstance (). NewXMLGregorianCalendar (neuer GregorianCalendar (JJJJ, MM, TT));
Junchen Liu
3
Bitte beachten Sie, dass der Kalender nicht threadsicher ist und daher auch der Gregorianische Kalender nicht. Siehe auch stackoverflow.com/questions/12131324/…
Fragebogen
Einzeilige Version - DatatypeFactory.newInstance (). NewXMLGregorianCalendar (neuer GregorianCalendar () {{setTime (yourDate);}})
Alex Vayda
205

Für diejenigen, die hier landen könnten und nach der entgegengesetzten Konvertierung suchen (von XMLGregorianCalendarnach Date):

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

Hier ist eine Methode zum Konvertieren von einem GregorianCalendar in einen XMLGregorianCalendar. Ich überlasse den Teil der Konvertierung von java.util.Date in GregorianCalendar als Übung für Sie:

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
quelle
6
Dies ist eine Lösung, um GregorianCalendar in XMLGregorianCalendar zu konvertieren und nicht das, was in der Frage angegeben ist
ftrujillo
12

Ich dachte nur, ich würde meine Lösung unten hinzufügen, da die obigen Antworten nicht genau meinen Anforderungen entsprachen. Für mein XML-Schema waren separate Datums- und Uhrzeitelemente erforderlich, kein einzelnes DateTime-Feld. Der oben verwendete Standardkonstruktor XMLGregorianCalendar generiert ein DateTime-Feld

Beachten Sie, dass es einige Gothcas gibt, z. B. das Hinzufügen eines Monats zum Monat (da Java Monate von 0 zählt).

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

Ich hoffe, meine Codierung hier ist richtig; D Um es schneller zu machen, verwenden Sie einfach den hässlichen getInstance () -Aufruf von GregorianCalendar anstelle des Konstruktoraufrufs:

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.
quelle
14
-1 für die Verwendung von .getInstance (). GregorianCalendar.getInstance()ist das Äquivalent von Calendar.getInstance(). Das Calendar.getInstance()kann es nicht schneller machen, weil es dasselbe verwendet new GregorianCalendar(), aber bevor es auch das Standardgebietsschema überprüft und stattdessen einen japanischen oder Buddish-Kalender erstellen könnte, wird es für einige glückliche Benutzer so sein ClassCastException!
Kan
6

Angenommen, Sie dekodieren oder codieren XML und verwenden XML JAXB, dann ist es möglich, die dateTime-Bindung vollständig zu ersetzen und für jedes Datum im Schema etwas anderes als "XMLGregorianCalendar" zu verwenden.

Auf diese Weise können Sie haben JAXB Sie die sich wiederholenden Dinge erledigen, während Sie die Zeit damit verbringen können, fantastischen Code zu schreiben, der Wert liefert.

Beispiel für eine Jodatime DateTime: (Dies mit java.util.Date zu tun würde auch funktionieren - aber mit bestimmten Einschränkungen. Ich bevorzuge Jodatime und es wird aus meinem Code kopiert, damit ich weiß, dass es funktioniert ...)

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

Und der Konverter:

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

Siehe hier: Wie kann XmlGregorianCalendar durch Datum ersetzt werden?

Wenn Sie gerne nur einen Moment basierend auf der Zeitzone + dem Zeitstempel zuordnen und die ursprüngliche Zeitzone nicht wirklich relevant ist, java.util.Dateist dies wahrscheinlich auch in Ordnung.

KarlP
quelle
0

Überprüfen Sie diesen 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);

Das vollständige Beispiel finden Sie hier

Akash
quelle
Ich glaube nicht, dass diese Antwort nichts Neues bietet. Vielleicht können Sie die vorherige Antwort bearbeiten, anstatt eine andere fast gleich zu posten.
Winter
1
Wie erstelle ich ein dateFormat für XMLGregorianCalendar?
Panadol Chong