Jawaban:
Saya ingin mengambil langkah mundur dan melihat modern pada pertanyaan berumur 10 tahun ini. Kelas-kelas yang disebutkan, Date
dan XMLGregorianCalendar
, sudah tua sekarang. Saya menantang penggunaan mereka dan menawarkan alternatif.
Date
selalu dirancang dengan buruk dan berusia lebih dari 20 tahun. Ini sederhana: jangan gunakan itu.XMLGregorianCalendar
sudah 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:00
atau 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.Untuk banyak tujuan (sebagian besar?) Pengganti modern untuk Date
akan menjadi Instant
. An Instant
adalah 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 XMLGregorianCalendar
string saya di atas. Seperti sebagian besar dari Anda tahu, itu berasal dari Instant.toString
dipanggil secara implisit System.out.println
. Dengan java.time, dalam banyak kasus kita tidak perlu konversi yang di hari tua kita dibuat antara Date
, Calendar
, XMLGregorianCalendar
dan kelas-kelas lain (dalam beberapa kasus kita lakukan konversi kebutuhan, meskipun, saya menunjukkan kepada Anda beberapa di bagian berikutnya) .
Baik a Date
maupun in tidak Instant
memiliki 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 zone
ke ZoneId.systemDefault()
.
Ada banyak cara untuk mengkonversi Instant
ke XMLGregorianCalendar
. Saya akan menyajikan pasangan, masing-masing dengan pro dan kontra. Pertama, seperti halnya XMLGregorianCalendar
menghasilkan 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.
Jika Anda mendapatkan Date
objek 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 OffsetDateTime
dalam dengan cara yang sama seperti di atas.
Jika Anda memiliki model lama Date
dan benar-benar membutuhkan model lama XMLGregorianCalendar
, gunakan saja jawaban oleh Ben Noland.
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
Bagi yang mungkin berakhir di sini mencari konversi yang berlawanan (dari XMLGregorianCalendar
ke Date
):
XMLGregorianCalendar xcal = <assume this is initialized>;
java.util.Date dt = xcal.toGregorianCalendar().getTime();
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 :-)
Contoh satu baris menggunakan perpustakaan Joda-Time :
XMLGregorianCalendar xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(new DateTime().toGregorianCalendar());
Penghargaan untuk Nicolas Mommaerts dari komentarnya dalam jawaban yang diterima .
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);
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);
}
}
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
!
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 JAXB
melakukan 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.Date
mungkin juga baik-baik saja.
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
ZonedDateTime
kelas, dan metode konversi baru ditambahkan ke kelas lawas. Detail dalam Jawaban ini oleh Ole VV