java.util.Date to XMLGregorianCalendar


601

Разве нет удобного способа получить из java.util.Date XMLGregorianCalendar?


К вашему сведению: Оба этих ужасных класса были вытеснены несколько лет назад классами 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, современного Java-API даты и времени, могут создавать их, что мы предпочитаем.

Нет необходимости в преобразовании

Для многих (большинства?) Целей современная замена 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и другие классы (в некоторых случаях мы делаем преобразование нужно, хотя, я показываю вам пару в следующем разделе) ,

Управление смещением

Ни у, 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. Я представлю пару, каждая со своими плюсами и минусами. Во-первых, подобно тому, как a 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: это коротко, и я не думаю, что это преподносит какие-либо сюрпризы. 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

Pro: Это официальное преобразование. Управление смещением происходит естественно. Против: он проходит больше шагов и, следовательно, дольше.

Что если у нас будет свидание?

Если вы получили устаревший Dateобъект из унаследованного API, который вы не можете сейчас изменить, преобразуйте его в Instant:

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

Вывод такой же, как и раньше:

2009-05-07T17: 05: 45.678Z

Если вы хотите управлять смещением, преобразуйте далее в a так 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 (new DateTime (). ToGregorianCalendar ())
Николас Момэрц

3
XMLGregorianCalendar date2 = DatatypeFactory.newInstance (). NewXMLGregorianCalendar (new GregorianCalendar (YYYY, MM, DD));
Junchen Лю

3
Пожалуйста, имейте в виду, что Календарь не является потокобезопасным, и поэтому GregorianCalender - нет. См. Также stackoverflow.com/questions/12131324/…
вопросник

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

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-схема требует отдельных элементов Date и Time, а не отдельного поля DateTime. Стандартный конструктор XMLGregorianCalendar, использованный выше, будет генерировать поле DateTime

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

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(), но прежде чем он также проверяет локаль по умолчанию и может вместо этого создать японский или буддийский календарь, так что для некоторых счастливчиков это будет 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 на Date?

Если вы счастливы просто отобразить момент, основанный на временной зоне + временная метка, и исходная временная зона не очень актуальна, то 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
Как сделать dateFormat для XMLGregorianCalendar?
Панадол Чонг
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.