Yanıtlar:
Bu 10 yıllık soruya geri adım atmak ve modern bir bakış atmak istiyorum. Bahsedilen sınıflar Date
ve XMLGregorianCalendar
şimdi eskidir. Bunların kullanımına meydan okuyorum ve alternatifler sunuyorum.
Date
her zaman kötü tasarlanmış ve 20 yıldan daha eski. Bu basit: kullanma.XMLGregorianCalendar
çok eskidir ve eski moda bir tasarıma sahiptir. Anladığım kadarıyla, XML belgeleri için XML formatında tarih ve saat üretmek için kullanıldı. Gibi 2009-05-07T19:05:45.678+02:00
veya 2009-05-07T17:05:45.678Z
. Bu formatlar, modern Java tarih ve saat API'sı olan java.time sınıflarının bunları tercih edebileceğimiz ISO 8601 ile yeterince uyumludur.Birçok (en?) Amaçlar için bir modern yerine bir Date
olacaktır Instant
. An Instant
zamandaki bir noktadır (aynen olduğu gibi Date
).
Instant yourInstant = // ...
System.out.println(yourInstant);
Bu snippet'ten bir örnek çıktı:
2009-05-07T17: 05: 45.678Z
XMLGregorianCalendar
Yukarıdaki örnek dizelerimin ikincisi ile aynı . Çoğunuzun bildiği gibi, Instant.toString
dolaylı olarak çağrılmaktan gelir System.out.println
. Java.time ile birçok durumda eski günlerdeki biz arasında yapılan bu dönüşümleri gerekmez Date
, Calendar
, XMLGregorianCalendar
ve diğer sınıflar (biz ihtiyaç dönüşümleri yapmak bazı durumlarda olsa, sana sonraki bölümde birkaç gösteriyorum) .
Ne Date
ne de ne Instant
bir saat dilimi ne de UTC dengesi yoktur. Ben Noland'ın daha önce kabul edilmiş ve hala en yüksek oyu alan cevabı, JVM'lerin ofsetini seçmek için geçerli varsayılan saat dilimini kullanır XMLGregorianCalendar
. Modern bir nesneye ofset eklemek için bir OffsetDateTime
. Örneğin:
ZoneId zone = ZoneId.of("America/Asuncion");
OffsetDateTime dateTime = yourInstant.atZone(zone).toOffsetDateTime();
System.out.println(dateTime);
2009-05-07T13: 05: 45,678-04: 00
Yine bu XML formatına uygundur. Tekrar geçerli JVM saat dilimi ayarını kullanmak istiyorsanız, set zone
için ZoneId.systemDefault()
.
Dönüştürmek Instant
için daha fazla yol var XMLGregorianCalendar
. Her biri artıları ve eksileri olan bir çift sunacağım. İlk olarak, tıpkı XMLGregorianCalendar
bir dize ürettiği gibi 2009-05-07T17:05:45.678Z
, böyle bir dizeden de oluşturulabilir:
String dateTimeString = yourInstant.toString();
XMLGregorianCalendar date2
= DatatypeFactory.newInstance().newXMLGregorianCalendar(dateTimeString);
System.out.println(date2);
2009-05-07T17: 05: 45.678Z
Pro: Kısa ve sürprizler olduğunu düşünmüyorum. Con: Bana göre, anı bir dizeye biçimlendiren ve onu ayrıştıran bir atık gibi geliyor.
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: Bu resmi dönüşüm. Ofseti kontrol etmek doğal olarak gelir. Con: Daha fazla adım atıyor ve bu nedenle daha uzun.
Date
Eski bir API'dan, şimdi değiştirmeyi göze alamayacağınız eski moda bir nesneniz varsa, şu biçime dönüştürün Instant
:
Instant i = yourDate.toInstant();
System.out.println(i);
Çıktı öncekiyle aynı:
2009-05-07T17: 05: 45.678Z
Ofseti kontrol etmek istiyorsanız OffsetDateTime
, yukarıdakiyle aynı şekilde daha ileriye dönüştürün .
Eski modaya sahipseniz Date
ve kesinlikle eski modaya ihtiyacınız varsa XMLGregorianCalendar
, Ben Noland'ın cevabını kullanın.
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
Burada karşıt dönüşümü arayanlar için ( XMLGregorianCalendar
ila arasında Date
):
XMLGregorianCalendar xcal = <assume this is initialized>;
java.util.Date dt = xcal.toGregorianCalendar().getTime();
İşte bir GregorianCalendar XMLGregorianCalendar dönüştürmek için bir yöntem; Bir java.util.Date'den GregorianCalendar'e dönüştürme işlemini sizin için bir egzersiz olarak bırakacağım:
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);
}
}
DÜZENLEME: Slooow :-)
Joda-Time kitaplığını kullanan tek satırlık bir örnek :
XMLGregorianCalendar xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(new DateTime().toGregorianCalendar());
Kredi Nicolas Mommaerts yaptığı yorumun kabul cevap .
Yukarıdaki cevapları tam olarak karşılayamadığım için çözümümü aşağıya ekleyeceğimi düşündüm. Xml şemam, tek bir DateTime alanı değil, ayrı Tarih ve Saat öğelerini gerektiriyordu. Yukarıda kullanılan standart XMLGregorianCalendar yapıcısı bir DateTime alanı oluşturur
Ay'a bir tane eklemek zorunda gibi birkaç gothca var (java 0'dan ayları saydığı için).
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);
Ben burada kodlama doğru olduğunu umuyoruz; D Daha hızlı yapmak için sadece yapıcı çağrı yerine GregorianCalendar çirkin getInstance () çağrısı kullanın:
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()
eşdeğeridir Calendar.getInstance()
. Daha Calendar.getInstance()
hızlı yapamaz, çünkü aynı kullanır new GregorianCalendar()
, ancak aynı zamanda varsayılan yerel ayarı kontrol eder ve bunun yerine Japonca veya Budist takvimi oluşturabilir, bu yüzden bazı şanslı kullanıcılar için olacak ClassCastException
!
Xml kodunu JAXB
çözdüğünüz veya kodladığınızı varsayarsak, dateTime bağlamasını tamamen değiştirmek ve şemadaki her tarih için `XMLGregorianCalendar 'dan başka bir şey kullanmak mümkündür.
Böylece JAXB
değer veren müthiş bir kod yazmak için zaman harcayabilirsiniz tekrarlayan şeyler yapmak zorunda.
Bir jodatime örneği DateTime
: (Bunu java.util.Date ile yapmak da işe yarayacaktır - ancak bazı sınırlamalar ile.
<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>
Ve dönüştürücü:
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);
}
}
Buraya bakın: XmlGregorianCalendar'ı tarihe göre nasıl değiştirebilirim?
Saat dilimi + zaman damgasına dayalı bir anı eşlemekten mutluluk duyuyorsanız ve orijinal saat dilimi gerçekten alakalı değilse java.util.Date
, muhtemelen de iyidir.
Bu kodu inceleyin: -
/* 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);
Tüm örneği burada görebilirsiniz
ZonedDateTime
Sınıf ve eski sınıflara eklenen yeni dönüştürme yöntemleri konusuna bakın . Bu Cevapla Ayrıntılar Ole VV