Java.util.Date для XMLGregorianCalendar

Нет ли удобного способа перехода из java.util.Date в XMLGregorianCalendar?

Ответ 1

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

    Instant yourInstant = // ...
    System.out.println(yourInstant);

Пример вывода из этого фрагмента:

2009-05-07T17: 05: 45.678Z

Это так же, как последний из моих примеров строк XMLGregorianCalendar выше. Как большинство из вас знает, это происходит из Instant.toString который неявно 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

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

Если вы хотите управлять смещением, преобразуйте далее в OffsetDateTime же, как описано выше.

Если вы получили старомодную Date и абсолютно нуждаетесь в старомодном XMLGregorianCalendar, просто воспользуйтесь ответом Бена Ноланда.

связи

Ответ 2

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

Ответ 3

Для тех, кто может найти здесь обратное преобразование (от XMLGregorianCalendar до Date):

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

Ответ 4

Вот способ преобразования из 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);
   }

}

EDIT: Slooow: -)

Ответ 5

Пример из одной строки с использованием Joda-Time:

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

Кредит Nicolas Mommaerts из его комментария в принятом ответе.

Ответ 6

Просто подумал, что добавлю свое решение ниже, так как приведенные выше ответы не соответствовали моим конкретным потребностям. В моей схеме Xml требуются отдельные элементы Date и Time, а не однопользовательское поле 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);

Ответ 7

Надеюсь, моя кодировка верна, 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);
   }

}

Ответ 8

Предполагая, что вы декодируете или кодируете 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, вероятно, тоже хорошо.

Ответ 9

Проверьте этот код: -

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

Вы можете увидеть полный пример здесь