java.util. Tanggal ke XMLGregorianCalendar

601

Apakah tidak ada cara mudah untuk mendapatkan dari java.util.Date ke XMLGregorianCalendar?

Mac
sumber
FYI: Kedua kelas mengerikan ini digantikan bertahun-tahun yang lalu oleh kelas java.time yang didefinisikan dalam JSR 310. Lihat ZonedDateTimekelas, dan metode konversi baru ditambahkan ke kelas lawas. Detail dalam Jawaban ini oleh Ole VV
Basil Bourque

Jawaban:

36

Saya ingin mengambil langkah mundur dan melihat modern pada pertanyaan berumur 10 tahun ini. Kelas-kelas yang disebutkan, Datedan XMLGregorianCalendar, sudah tua sekarang. Saya menantang penggunaan mereka dan menawarkan alternatif.

  • Dateselalu dirancang dengan buruk dan berusia lebih dari 20 tahun. Ini sederhana: jangan gunakan itu.
  • XMLGregorianCalendarsudah tua juga dan memiliki desain kuno. Seperti yang saya pahami, ini digunakan untuk menghasilkan tanggal dan waktu dalam format XML untuk dokumen XML. Suka 2009-05-07T19:05:45.678+02:00atau 2009-05-07T17:05:45.678Z. Format ini cukup sesuai dengan ISO 8601 sehingga kelas java.time, API tanggal dan waktu Jawa modern, dapat memproduksinya, yang kami inginkan.

Tidak perlu konversi

Untuk banyak tujuan (sebagian besar?) Pengganti modern untuk Dateakan menjadi Instant. An Instantadalah titik waktu (sama seperti apa adanya Date).

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

Contoh output dari cuplikan ini:

2009-05-07T17: 05: 45.678Z

Itu sama dengan yang terakhir dari contoh XMLGregorianCalendarstring saya di atas. Seperti sebagian besar dari Anda tahu, itu berasal dari Instant.toStringdipanggil secara implisit System.out.println. Dengan java.time, dalam banyak kasus kita tidak perlu konversi yang di hari tua kita dibuat antara Date, Calendar, XMLGregorianCalendardan kelas-kelas lain (dalam beberapa kasus kita lakukan konversi kebutuhan, meskipun, saya menunjukkan kepada Anda beberapa di bagian berikutnya) .

Mengontrol offset

Baik a Datemaupun in tidak Instantmemiliki zona waktu atau offset UTC. Jawaban yang diterima sebelumnya dan masih dinilai tertinggi oleh Ben Noland menggunakan zona waktu default JVM saat ini untuk memilih offset dari XMLGregorianCalendar. Untuk memasukkan offset dalam objek modern, kami menggunakan OffsetDateTime. Sebagai contoh:

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

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

Sekali lagi ini sesuai dengan format XML. Jika Anda ingin menggunakan pengaturan zona waktu JVM saat ini lagi, atur zoneke ZoneId.systemDefault().

Bagaimana jika saya benar-benar membutuhkan XMLGregorianCalendar?

Ada banyak cara untuk mengkonversi Instantke XMLGregorianCalendar. Saya akan menyajikan pasangan, masing-masing dengan pro dan kontra. Pertama, seperti halnya XMLGregorianCalendarmenghasilkan string 2009-05-07T17:05:45.678Z, itu juga dapat dibangun dari string seperti itu:

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

2009-05-07T17: 05: 45.678Z

Pro: pendek dan saya pikir itu tidak memberikan kejutan. Con: Bagi saya rasanya seperti memformat instan menjadi string dan mem-parsingnya kembali.

    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: Ini adalah konversi resmi. Mengontrol offset datang secara alami. Con: Ini melewati lebih banyak langkah dan karena itu lebih lama.

Bagaimana jika kita mendapat kencan?

Jika Anda mendapatkan Dateobjek kuno dari API lawas yang tidak mampu Anda ubah sekarang, konversikan ke Instant:

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

Outputnya sama seperti sebelumnya:

2009-05-07T17: 05: 45.678Z

Jika Anda ingin mengontrol offset, konversikan lebih jauh ke OffsetDateTimedalam dengan cara yang sama seperti di atas.

Jika Anda memiliki model lama Datedan benar-benar membutuhkan model lama XMLGregorianCalendar, gunakan saja jawaban oleh Ben Noland.

Tautan

Ole VV
sumber
1034
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
Ben Noland
sumber
5
Apakah menyimpan untuk menjaga getInstance () sebagai variabel statis di beberapa kelas konverter? Saya mencoba mencarinya di JavaDoc tetapi tidak menemukan apa pun. Agak sulit untuk mengetahui apakah akan ada masalah dalam penggunaan bersamaan?
Martin
36
Jika Anda bersedia untuk menggunakan JodaTime Anda dapat melakukan ini dalam satu baris: DatatypeFactory.newInstance () newXMLGregorianCalendar. (DateTime baru () toGregorianCalendar ().)
Nicolas Mommaerts
3
XMLGregorianCalendar date2 = DatatypeFactory.newInstance (). NewXMLGregorianCalendar (GregorianCalendar baru (YYYY, MM, DD));
Junchen Liu
3
Perlu diketahui bahwa Kalender bukan threadsafe dan karenanya GregorianCalender tidak. Lihat juga stackoverflow.com/questions/12131324/…
questionaire
Versi satu baris - DatatypeFactory.newInstance (). NewXMLGregorianCalendar (GregorianCalendar baru () {{setTime (yourDate);}})
Alex Vayda
205

Bagi yang mungkin berakhir di sini mencari konversi yang berlawanan (dari XMLGregorianCalendarke Date):

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

Berikut adalah metode untuk mengkonversi dari GregorianCalendar ke XMLGregorianCalendar; Saya akan meninggalkan bagian konversi dari java.util.Date ke GregorianCalendar sebagai latihan untuk Anda:

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
sumber
6
Ini solusi untuk mengkonversi GregorianCalendar ke XMLGregorianCalendar dan bukan apa yang ditunjukkan dalam pertanyaan
ftrujillo
12

Saya pikir saya akan menambahkan solusi saya di bawah ini, karena jawaban di atas tidak memenuhi kebutuhan saya yang sebenarnya. Skema Xml saya membutuhkan elemen Tanggal dan Waktu yang terpisah, bukan bidang DateTime yang baru. Konstruktor XMLGregorianCalendar standar yang digunakan di atas akan menghasilkan bidang DateTime

Perhatikan ada beberapa gothca, seperti harus menambahkan satu ke bulan (karena java menghitung bulan dari 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
sumber
10

Saya harap penyandian saya di sini benar; D Untuk membuatnya lebih cepat cukup gunakan panggilan getInstance () jelek dari GregorianCalendar alih-alih panggilan konstruktor:

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.
sumber
14
-1 untuk menggunakan .getInstance (). GregorianCalendar.getInstance()adalah setara dengan Calendar.getInstance(). Tidak Calendar.getInstance()dapat membuatnya lebih cepat, karena menggunakan yang sama new GregorianCalendar(), tetapi sebelum itu juga memeriksa lokal default dan dapat membuat kalender Jepang atau Buddish, jadi bagi beberapa pengguna yang beruntung itu akan menjadi ClassCastException!
kan
6

Dengan anggapan Anda sedang mendekode atau menyandikan xml dan menggunakan JAXB, maka dimungkinkan untuk mengganti penjilidan dateTime sepenuhnya dan menggunakan sesuatu yang lain selain `XMLGregorianCalendar 'untuk setiap tanggal dalam skema.

Dengan cara itu Anda dapat JAXBmelakukan hal-hal yang berulang sementara Anda dapat menghabiskan waktu untuk menulis kode yang luar biasa yang memberikan nilai.

Contoh untuk jodatime DateTime: (Melakukan ini dengan java.util.Date juga akan berfungsi - tetapi dengan batasan tertentu. Saya lebih suka jodatime dan disalin dari kode saya jadi saya tahu itu berfungsi ...)

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

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

Lihat di sini: bagaimana cara mengganti XmlGregorianCalendar berdasarkan Tanggal?

Jika Anda senang hanya memetakan ke instan berdasarkan zona waktu + timestamp, dan zona waktu asli tidak benar-benar relevan, maka java.util.Datemungkin juga baik-baik saja.

KarlP
sumber
0

Lihat kode ini: -

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

Anda dapat melihat contoh lengkapnya di sini

Akash
sumber
Saya tidak berpikir bahwa jawaban ini tidak memberikan sesuatu yang baru .. Mungkin Anda dapat mengedit jawaban sebelumnya alih-alih memposting yang lain hampir sama.
musim dingin
1
Bagaimana cara melakukan dateFormat untuk XMLGregorianCalendar?
Panadol Chong