คำตอบ:
ฉันควรจะย้อนกลับไปและดูคำถามอายุ 10 ปีที่ทันสมัย ชั้นเรียนที่กล่าวถึงDate
และXMLGregorianCalendar
เก่าไปแล้ว ฉันท้าทายการใช้งานและเสนอทางเลือกอื่น ๆ
Date
ออกแบบมาไม่ดีและมีอายุมากกว่า 20 ปี ง่ายมากอย่าใช้มันXMLGregorianCalendar
เก่าเกินไปและมีการออกแบบที่ล้าสมัย อย่างที่ฉันเข้าใจมันใช้สำหรับการสร้างวันที่และเวลาในรูปแบบ XML สำหรับเอกสาร XML กดไลค์2009-05-07T19:05:45.678+02:00
หรือ 2009-05-07T17:05:45.678Z
รูปแบบเหล่านี้มีความสอดคล้องที่ดีกับ ISO 8601 ซึ่งคลาสของ java.time ซึ่งเป็นวันที่และเวลา API ของ Java สมัยใหม่สามารถสร้างได้ตามที่เราต้องการสำหรับหลาย ๆ คน (ส่วนใหญ่) มีวัตถุประสงค์เพื่อการทดแทนที่ทันสมัยสำหรับจะเป็นDate
Instant
An Instant
เป็นจุดในเวลา (เช่นเดียวกับที่เป็นDate
อยู่)
Instant yourInstant = // ...
System.out.println(yourInstant);
ตัวอย่างผลลัพธ์จากตัวอย่างนี้:
2009-05-07T17: 05: 45.678Z
มันเหมือนกับXMLGregorianCalendar
สตริงตัวอย่างด้านบนของฉัน เป็นส่วนใหญ่ของคุณรู้ว่ามันมาจากการถูกเรียกโดยปริยายInstant.toString
System.out.println
ด้วย java.time ในหลายกรณีเราไม่จำเป็นต้องแปลงที่ว่าในวันเก่าที่เราทำขึ้นระหว่างDate
, Calendar
,XMLGregorianCalendar
และชั้นเรียนอื่น ๆ (ในบางกรณีที่เราทำแปลงจำเป็น แต่ผมกำลังแสดงคู่ในส่วนถัดไป) .
a Date
หรือ in ไม่Instant
ได้มีเขตเวลาหรือออฟเซ็ต UTC คำตอบที่ได้รับการยอมรับก่อนหน้านี้และยังคงสูงที่สุดโหวตโดยเบน Noland ใช้โซนเวลาเริ่มต้น JVMs ปัจจุบันสำหรับการเลือก offset XMLGregorianCalendar
ของ OffsetDateTime
จะรวมถึงการชดเชยในวัตถุที่ทันสมัยเราใช้ ตัวอย่างเช่น:
ZoneId zone = ZoneId.of("America/Asuncion");
OffsetDateTime dateTime = yourInstant.atZone(zone).toOffsetDateTime();
System.out.println(dateTime);
2009-05-07T13: 05: 45.678-04: 00
อีกครั้งนี้สอดคล้องกับรูปแบบ XML หากคุณต้องการใช้การตั้งค่าโซนเวลาปัจจุบัน JVM อีกครั้งตั้งไปzone
ZoneId.systemDefault()
มีวิธีการอื่น ๆ ในการแปลงเป็นไปInstant
XMLGregorianCalendar
ฉันจะนำเสนอคู่แต่ละคนมีข้อดีและข้อเสียของมัน ครั้งแรกเช่นเดียวกับที่XMLGregorianCalendar
ผลิตสตริงเช่น2009-05-07T17:05:45.678Z
นั้นมันยังสามารถสร้างจากสตริงดังกล่าว:
String dateTimeString = yourInstant.toString();
XMLGregorianCalendar date2
= DatatypeFactory.newInstance().newXMLGregorianCalendar(dateTimeString);
System.out.println(date2);
2009-05-07T17: 05: 45.678Z
Pro: มันสั้นและฉันไม่คิดว่ามันจะสร้างความประหลาดใจใด ๆ คอนดิชั่น: สำหรับฉันแล้วมันรู้สึกเหมือนว่าเป็นการเสียรูปแบบของข้อความโต้ตอบแบบทันทีในสตริง
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: มันคือการแปลงอย่างเป็นทางการ การควบคุมออฟเซตมาตามธรรมชาติ คอนดิชั่น: มันจะผ่านขั้นตอนมากขึ้นและดังนั้นจึงอีกต่อไป
หากคุณได้รับDate
วัตถุสมัยเก่าจาก API แบบเก่าที่คุณไม่สามารถเปลี่ยนแปลงได้ให้แปลงเป็นInstant
:
Instant i = yourDate.toInstant();
System.out.println(i);
ผลลัพธ์เหมือนก่อนหน้านี้:
2009-05-07T17: 05: 45.678Z
หากคุณต้องการควบคุมออฟเซ็ตให้แปลงต่อไปเป็นOffsetDateTime
แบบเดียวกับข้างบน
หากคุณมีความล้าสมัยDate
และต้องการความล้าสมัยอย่างแน่นอนXMLGregorianCalendar
เพียงใช้คำตอบของ Ben Noland
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
สำหรับผู้ที่อาจสิ้นสุดที่นี่มองหาการแปลงตรงข้าม (จากXMLGregorianCalendar
ถึงDate
):
XMLGregorianCalendar xcal = <assume this is initialized>;
java.util.Date dt = xcal.toGregorianCalendar().getTime();
นี่คือวิธีการแปลงจาก GregorianCalendar เป็น XMLGregorianCalendar ฉันจะปล่อยให้ส่วนหนึ่งของการแปลงจาก java.util.Date เป็น GregorianCalendar เป็นการออกกำลังกายสำหรับคุณ:
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);
}
}
แก้ไข: Slooow :-)
ตัวอย่างหนึ่งบรรทัดโดยใช้ไลบรารีJoda-Time :
XMLGregorianCalendar xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(new DateTime().toGregorianCalendar());
ให้เครดิตกับNicolas Mommaertsจากความคิดเห็นของเขาในคำตอบที่ยอมรับได้
แค่คิดว่าฉันจะเพิ่มวิธีแก้ปัญหาของฉันด้านล่างเนื่องจากคำตอบข้างต้นไม่ตรงกับความต้องการที่แท้จริงของฉัน สกีมา Xml ของฉันต้องแยกองค์ประกอบวันที่และเวลาไม่ใช่ฟิลด์ DateTime ตัวสร้าง XMLGregorianCalendar มาตรฐานที่ใช้ด้านบนจะสร้างฟิลด์ DateTime
หมายเหตุมี gothca สองสามรายการเช่นต้องเพิ่มหนึ่งเดือน (ตั้งแต่ java นับเดือนจาก 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);
ฉันหวังว่าการเข้ารหัสของฉันที่นี่ถูกต้อง D เพื่อให้เร็วขึ้นเพียงใช้การเรียก getInstance () ที่น่าเกลียดของ GregorianCalendar แทนการเรียก constructor:
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()
ไม่สามารถทำให้มันเร็วขึ้นเพราะมันใช้เหมือนกันแต่ก่อนที่มันจะยังตรวจสอบสถานที่เกิดเหตุเริ่มต้นและสามารถสร้างภาษาญี่ปุ่นหรือ Buddish ปฏิทินแทนดังนั้นสำหรับผู้ใช้ที่โชคดีบางอย่างมันจะเป็น! Calendar.getInstance()
Calendar.getInstance()
new GregorianCalendar()
ClassCastException
สมมติว่าคุณกำลังถอดรหัสหรือเข้ารหัส xml และใช้JAXB
คุณสามารถแทนที่ dateTime ทั้งหมดและใช้อย่างอื่นนอกเหนือจาก `XMLGregorianCalendar 'สำหรับทุก ๆ วันใน schema
ด้วยวิธีการที่คุณสามารถมี JAXB
ทำสิ่งซ้ำ ๆ ได้ในขณะที่คุณสามารถใช้เวลาในการเขียนโค้ดที่ยอดเยี่ยมที่ให้คุณค่า
ตัวอย่างสำหรับ jodatime DateTime
: (การทำเช่นนี้กับ java.util.Date จะใช้งานได้ - แต่มีข้อ จำกัด บางอย่างฉันชอบ jodatime และคัดลอกมาจากรหัสของฉันดังนั้นฉันจึงรู้ว่ามันใช้งานได้ ... )
<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>
และตัวแปลง:
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);
}
}
ดูที่นี่: วิธีแทนที่ XmlGregorianCalendar ตามวันที่
หากคุณมีความสุขที่จะแมปไปยังทันทีตามเขตเวลา + การประทับเวลาและเขตเวลาดั้งเดิมนั้นไม่เกี่ยวข้องกันจริงๆก็java.util.Date
อาจจะใช้ได้เช่นกัน
ลองดูรหัสนี้: -
/* 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);
คุณสามารถดูตัวอย่างสมบูรณ์ได้ที่นี่
ZonedDateTime
คลาสและวิธีการแปลงใหม่ที่เพิ่มในคลาสดั้งเดิม รายละเอียดในคำตอบนี้โดย Ole VV