code

java.util.Date에서 XMLGregorianCalendar로

codestyles 2020. 10. 3. 10:44
반응형

java.util.Date에서 XMLGregorianCalendar로


java.util.Date에서 XMLGregorianCalendar로 이동하는 편리한 방법이 없습니까?


나는 한 걸음 물러나서이 10 년 된 질문을 현대적으로 살펴보고 싶습니다. 언급 된 클래스 DateXMLGregorianCalendar은 (는) 현재 오래되었습니다. 나는 그것들의 사용에 도전하고 대안을 제시합니다.

  • Date항상 형편없이 설계되었고 20 년이 넘었습니다. 이것은 간단합니다. 사용하지 마십시오.
  • XMLGregorianCalendar너무 오래되었고 구식 디자인이 있습니다. 내가 알기로는 XML 문서의 XML 형식으로 날짜와 시간을 생성하는 데 사용되었습니다. 좋아요 2009-05-07T19:05:45.678+02:00또는 2009-05-07T17:05:45.678Z. 이러한 형식은 최신 Java 날짜 및 시간 API 인 java.time 클래스가 우리가 선호하는 형식을 생성 할 수 있다는 점에서 ISO 8601과 충분히 일치합니다.

변환이 필요하지 않습니다.

많은 (대부분?) 목적을 위해를 현대적으로 대체 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을 사용하면 많은 경우 DateCalendar,, XMLGregorianCalendar및 다른 클래스 간에 이전에 만든 변환이 필요하지 않습니다 (일부 경우 변환이 필요하지만 다음 섹션에서 몇 가지를 보여 드리겠습니다). .

오프셋 제어

a Date와 in 모두 Instant시간대 나 UTC 오프셋이 없습니다. Ben Noland가 이전에 수락하고 여전히 가장 많이 투표 한 답변은 JVM의 현재 기본 시간대를 사용하여 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

장점 : 짧고 놀라움을주지 않는다고 생각합니다. 단점 : 나에게는 인스턴트를 문자열로 포맷하고 다시 파싱하는 것이 낭비처럼 느껴집니다.

    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

장점 : 공식적인 전환입니다. 오프셋 제어는 자연스럽게 이루어집니다. 단점 : 더 많은 단계를 거치므로 더 길어집니다.

데이트가 있으면?

Date레거시 API에서 지금 당장 변경할 수없는 구식 객체 를 얻은 경우 다음으로 변환하십시오 Instant.

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

출력은 이전과 동일합니다.

2009-05-07T17 : 05 : 45.678Z

오프셋을 제어하려면 OffsetDateTime위와 같은 방법으로 추가로 변환 하십시오.

구식이 Date있고 구식이 절대적으로 필요한 경우 XMLGregorianCalendarBen Noland의 답변을 사용하십시오.

연결


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

For those that might end up here looking for the opposite conversion (from XMLGregorianCalendar to Date):

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

Here is a method for converting from a GregorianCalendar to XMLGregorianCalendar; I'll leave the part of converting from a java.util.Date to GregorianCalendar as an exercise for you:

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


A one line example using Joda-Time library:

XMLGregorianCalendar xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(new DateTime().toGregorianCalendar());

Credit to Nicolas Mommaerts from his comment in the accepted answer.


Just thought I'd add my solution below, since the answers above did not meet my exact needs. My Xml schema required seperate Date and Time elements, not a singe DateTime field. The standard XMLGregorianCalendar constructor used above will generate a DateTime field

Note there a couple of gothca's, such as having to add one to the month (since java counts months from 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);

I hope my encoding here is right ;D To make it faster just use the ugly getInstance() call of GregorianCalendar instead of constructor call:

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

}

Assuming you are decoding or encoding xml and using JAXB, then it's possible to replace the dateTime binding entirely and use something else than `XMLGregorianCalendar' for every date in the schema.

In that way you can have JAXB do the repetitive stuff while you can spend the time on writing awesome code that delivers value.

Example for a jodatime DateTime: (Doing this with java.util.Date would also work - but with certain limitations. I prefer jodatime and it's copied from my code so I know it works...)

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

And the converter:

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

See here: how replace XmlGregorianCalendar by Date?

If you are happy to just map to an instant based on the timezone+timestamp, and the original timezone is not really relevant, then java.util.Date is probably fine too.


Check out this code :-

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

You can see complete example here

참고URL : https://stackoverflow.com/questions/835889/java-util-date-to-xmlgregoriancalendar

반응형