java.util.Date เป็น XMLGregorianCalendar


601

ไม่มีวิธีที่สะดวกในการรับจาก java.util.Date ไปเป็น XMLGregorianCalendar หรือไม่


FYI: คลาสที่แย่ทั้งสองนี้ถูกแทนที่เมื่อหลายปีก่อนโดยคลาสjava.time ที่กำหนดใน JSR 310 ดูZonedDateTimeคลาสและวิธีการแปลงใหม่ที่เพิ่มในคลาสดั้งเดิม รายละเอียดในคำตอบนี้โดย Ole VV
Basil Bourque

คำตอบ:


36

ฉันควรจะย้อนกลับไปและดูคำถามอายุ 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 InstantAn 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 อีกครั้งตั้งไปzoneZoneId.systemDefault()

ถ้าฉันต้องการ XMLGregorianCalendar จริงๆ

มีวิธีการอื่น ๆ ในการแปลงเป็นไป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

การเชื่อมโยง


1034
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);

5
มันบันทึกเพื่อให้ getInstance () เป็นตัวแปรคงที่ในบางระดับแปลง? ฉันพยายามค้นหามันใน JavaDoc แต่หาอะไรไม่เจอ อยากทราบว่าจะมีปัญหาในการใช้งานพร้อมกันหรือไม่
มาร์ติน

36
หากคุณยินดีที่จะใช้ JodaTime คุณสามารถทำได้ในหนึ่งบรรทัด: DatatypeFactory.newInstance (). newXMLGregorianCalendar (ใหม่ DateTime (). toGregorianCalendar ())
Nicolas Mommaerts

3
XMLGregorianCalendar date2 = DatatypeFactory.newInstance () .XMLGregorianCalendar ใหม่ (GregorianCalendar ใหม่ (YYYY, MM, DD));
Junchen Liu

3
โปรดทราบว่าปฏิทินไม่ใช่เธรดที่ปลอดภัยดังนั้น GregorianCalender ก็ไม่เช่นกัน ดูstackoverflow.com/questions/12131324/…
ถามคำถาม

รุ่นหนึ่งบรรทัด - DatatypeFactory.newInstance (). newXMLGregorianCalendar (GregorianCalendar ใหม่ () {{setTime (yourDate);}})
Alex Vayda

205

สำหรับผู้ที่อาจสิ้นสุดที่นี่มองหาการแปลงตรงข้าม (จากXMLGregorianCalendarถึงDate):

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

31

นี่คือวิธีการแปลงจาก 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 :-)


6
นี่เป็นทางออกในการแปลง GregorianCalendar เป็น XMLGregorianCalendar และไม่ใช่สิ่งที่ระบุไว้ในคำถาม
ftrujillo


12

แค่คิดว่าฉันจะเพิ่มวิธีแก้ปัญหาของฉันด้านล่างเนื่องจากคำตอบข้างต้นไม่ตรงกับความต้องการที่แท้จริงของฉัน สกีมา 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);

10

ฉันหวังว่าการเข้ารหัสของฉันที่นี่ถูกต้อง 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);
   }

}

14
-1 สำหรับการใช้. getInstance () เป็นเทียบเท่าของGregorianCalendar.getInstance() ไม่สามารถทำให้มันเร็วขึ้นเพราะมันใช้เหมือนกันแต่ก่อนที่มันจะยังตรวจสอบสถานที่เกิดเหตุเริ่มต้นและสามารถสร้างภาษาญี่ปุ่นหรือ Buddish ปฏิทินแทนดังนั้นสำหรับผู้ใช้ที่โชคดีบางอย่างมันจะเป็น! Calendar.getInstance()Calendar.getInstance()new GregorianCalendar()ClassCastException
kan

6

สมมติว่าคุณกำลังถอดรหัสหรือเข้ารหัส 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อาจจะใช้ได้เช่นกัน


0

ลองดูรหัสนี้: -

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

คุณสามารถดูตัวอย่างสมบูรณ์ได้ที่นี่


ฉันไม่คิดว่าคำตอบนี้จะไม่มีอะไรใหม่ .. บางทีคุณสามารถแก้ไขคำตอบก่อนหน้าแทนการโพสต์ข้อความอื่นเกือบเหมือนกัน
ฤดูหนาว

1
วิธีทำรูปแบบวันที่สำหรับ XMLGregorianCalendar
Panadol Chong
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.