java.util.Дати до XMLGregorianCalendar


601

Чи не існує зручного способу дістатися з java.util.Date до XMLGregorianCalendar?


FYI: Обидва ці жахливі класи були витіснені роками тому класами java.time, визначеними в JSR 310. Дивіться ZonedDateTimeклас та нові методи перетворення, додані до застарілих класів. Деталі у цьому відповіді Оле В. В.
Василь Бурк

Відповіді:


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заповіту буде Instant. А 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та інші класи (в деяких випадках ми робимо перетворення потрібно, хоча, я показую вам пару в наступному розділі) .

Контроль зміщення

Ні Dateні, ні ін. Не Instantмають часового поясу, ані зміщення UTC. Раніше прийнята і все ще найвища відповідь Бен Ноланд використовує поточний часовий пояс за замовчуванням 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, встановіть zoneзначення ZoneId.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

Про: він короткий, і я не думаю, що він не дає сюрпризів. Con: Для мене це схоже на марно відформатування миттєвості в рядок і розбору його назад.

    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і абсолютно потрібен старомодний XMLGregorianCalendar, просто скористайтеся відповіддю Бен Ноланда.

Посилання


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 (РРРР, ММ, DD));
Junchen Liu

3
Будь ласка, майте на увазі, що Календар не є безпечним для ниток, і тому також GregorianCalender не є. Дивіться також stackoverflow.com/questions/12131324/…
запитання

Версія однієї лінії - DatatypeFactory.newInstance (). NewXMLGregorianCalendar (новий GregorianCalendar () {{setTime (yourDate);}})
Алекс Вайда

205

Для тих, хто може закінчитися тут, шукаючи зворотну конверсію (від XMLGregorianCalendarдо Date):

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

31

Ось метод перетворення з GregorianCalendar в XMLGregorianCalendar; Я залишу частину перетворення з java.util.Дати в 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);
   }

}

EDIT: Slooow :-)


6
Це рішення для перетворення GregorianCalendar в XMLGregorianCalendar, а не те, що вказано у питанні
ftrujillo


12

Просто подумав, що я додам своє рішення нижче, оскільки відповіді вище не відповідали моїм точним потребам. Моя схема Xml вимагала окремих елементів дати та часу, а не окреме поле DateTime. Стандартний конструктор XMLGregorianCalendar, який використовується вище, генерує поле DateTime

Зверніть увагу на пару готк, таких як додавання до місяця (оскільки ява рахує місяці від 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 замість виклику конструктора:

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()є еквівалентом Calendar.getInstance(). Calendar.getInstance()Не можу зробити це швидше, тому що він використовує той же самий new GregorianCalendar(), але перш , ніж він також перевіряє регіональні настройки за замовчуванням і може створити японський або Buddish календар замість цього, так що для деяких щасливчиків користувачів це буде ClassCastException!
кан

6

Якщо припустити, що ви розшифровуєте або кодуєте xml та використовуєте JAXB, то можливо замінити прив'язку dateTime цілком і використовувати щось інше, ніж "XMLGregorianCalendar" для кожної дати в схемі.

Таким чином, ви можете 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.