Відповіді:
Мені б хотілося зробити крок назад і сучасний погляд на це 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()
.
Існує більше способів перетворення 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
, просто скористайтеся відповіддю Бен Ноланда.
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();
Ось метод перетворення з 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 :-)
Приклад в одному рядку з використанням бібліотеки Joda-Time :
XMLGregorianCalendar xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(new DateTime().toGregorianCalendar());
Кредит Ніколас Mommaerts з його коментаря в загальноприйнятому відповідь .
Просто подумав, що я додам своє рішення нижче, оскільки відповіді вище не відповідали моїм точним потребам. Моя схема 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);
Я сподіваюся, що моє кодування тут правильно; 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);
}
}
GregorianCalendar.getInstance()
є еквівалентом Calendar.getInstance()
. Calendar.getInstance()
Не можу зробити це швидше, тому що він використовує той же самий new GregorianCalendar()
, але перш , ніж він також перевіряє регіональні настройки за замовчуванням і може створити японський або Buddish календар замість цього, так що для деяких щасливчиків користувачів це буде ClassCastException
!
Якщо припустити, що ви розшифровуєте або кодуєте 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
, мабуть, також добре.
Перевірте цей код: -
/* 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);
Повний приклад ви можете подивитися тут
ZonedDateTime
клас та нові методи перетворення, додані до застарілих класів. Деталі у цьому відповіді Оле В. В.