Відповіді:
Мені б хотілося зробити крок назад і сучасний погляд на це 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клас та нові методи перетворення, додані до застарілих класів. Деталі у цьому відповіді Оле В. В.