java.util.Date to XMLGregorianCalendar
Разве нет удобного способа получить из java.util.Date XMLGregorianCalendar?
10 ответов
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
Для тех, кто может оказаться здесь в поисках противоположного преобразования (из XMLGregorianCalendar
в Date
):
XMLGregorianCalendar xcal = <assume this is initialized>;
java.util.Date dt = xcal.toGregorianCalendar().getTime();
Я хотел бы сделать шаг назад и по-современному взглянуть на этот 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
будучи неявно вызванным 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
Просто воспользуйтесь ответом Бена Ноланда.
связи
- Учебное пособие по Oracle: Date Time, объясняющее, как использовать java.time.
- Типы данных даты и времени XSD в W3Schools.
- Статья в Википедии: ISO 8601
Вот метод для преобразования из 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:-)
Пример из одной строки с использованием библиотеки Joda-Time:
XMLGregorianCalendar xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(new DateTime().toGregorianCalendar());
Nicolas Mommaerts из его комментария в принятом ответе.
Просто подумал, что я добавлю свое решение ниже, так как ответы выше не соответствуют моим точным потребностям. Моя 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);
Я надеюсь, что моя кодировка здесь правильна;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);
}
}
Предполагая, что вы декодируете или кодируете XML и используете JAXB
затем можно полностью заменить привязку dateTime и использовать что-то другое, кроме XMLGregorianCalendar для каждой даты в схеме.
Таким образом, вы можете иметь JAXB
делайте повторяющиеся вещи, пока вы можете потратить время на написание потрясающего кода, который приносит ценность.
Пример для йодатима 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
наверное тоже хорошо.
Проверьте этот код:-
/* 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);
Вы можете увидеть полный пример здесь
Мое решение
public static XMLGregorianCalendar DateToXMLGregorianCalendar(Date date) {
GregorianCalendar gregoriancalendar = new GregorianCalendar();
gregoriancalendar.setTime(date);
XMLGregorianCalendar xmlGregorianCalendar = new XMLGregorianCalendarImpl(gregoriancalendar);
return xmlGregorianCalendar;
}