Respostas:
Gostaria de dar um passo atrás e dar uma olhada moderna nesta questão de 10 anos de idade. As aulas mencionadas Date
e XMLGregorianCalendar
são antigas agora. Desafio o uso deles e ofereço alternativas.
Date
sempre foi mal projetado e tem mais de 20 anos. Isso é simples: não use.XMLGregorianCalendar
também é antigo e tem um design antiquado. Pelo que entendi, foi usado para produzir datas e horas no formato XML para documentos XML. Como 2009-05-07T19:05:45.678+02:00
ou 2009-05-07T17:05:45.678Z
. Esses formatos concordam bastante com a ISO 8601 para que as classes de java.time, a moderna API de data e hora de Java, possam produzi-las, como preferimos.Para muitos propósitos (a maioria?), A substituição moderna de a Date
será um Instant
. An Instant
é um ponto no tempo (exatamente como Date
é).
Instant yourInstant = // ...
System.out.println(yourInstant);
Um exemplo de saída deste snippet:
2009-05-07T17: 05: 45.678Z
É o mesmo que o último dos meus exemplos de XMLGregorianCalendar
strings acima. Como muitos de vocês sabem, vem de Instant.toString
ser implicitamente chamado por System.out.println
. Com java.time, em muitos casos, não precisamos das conversões que nos velhos tempos que fizemos entre Date
, Calendar
, XMLGregorianCalendar
e outras classes (em alguns casos, fazer conversões necessidade, porém, eu estou mostrando-lhe um par na próxima seção) .
Nem a Date
nem in Instant
possui um fuso horário nem um deslocamento UTC. A resposta anteriormente aceita e ainda mais votada por Ben Noland usa o fuso horário padrão atual da JVMs para selecionar o deslocamento da XMLGregorianCalendar
. Para incluir um deslocamento em um objeto moderno, usamos um OffsetDateTime
. Por exemplo:
ZoneId zone = ZoneId.of("America/Asuncion");
OffsetDateTime dateTime = yourInstant.atZone(zone).toOffsetDateTime();
System.out.println(dateTime);
2009-05-07T13: 05: 45.678-04: 00
Novamente, isso está em conformidade com o formato XML. Se você deseja usar a configuração atual do fuso horário da JVM novamente, defina zone
como ZoneId.systemDefault()
.
Existem mais maneiras de converter Instant
para XMLGregorianCalendar
. Vou apresentar um casal, cada um com seus prós e contras. Primeiro, assim como um XMLGregorianCalendar
produz uma string como 2009-05-07T17:05:45.678Z
, também pode ser construído a partir dessa string:
String dateTimeString = yourInstant.toString();
XMLGregorianCalendar date2
= DatatypeFactory.newInstance().newXMLGregorianCalendar(dateTimeString);
System.out.println(date2);
2009-05-07T17: 05: 45.678Z
Pro: é curto e acho que não dá nenhuma surpresa. Contras: Para mim, parece um desperdício formatar o instante em uma sequência e analisá-la novamente.
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: É a conversão oficial. Controlar o deslocamento ocorre naturalmente. Con: Ele passa por mais etapas e, portanto, é mais longo.
Se você obteve um Date
objeto antiquado de uma API herdada que não pode mudar agora, converta-o para Instant
:
Instant i = yourDate.toInstant();
System.out.println(i);
A saída é a mesma de antes:
2009-05-07T17: 05: 45.678Z
Se você deseja controlar o deslocamento, converta mais para um OffsetDateTime
da mesma maneira que acima.
Se você tem um antiquado Date
e absolutamente precisa de um antiquado XMLGregorianCalendar
, basta usar a resposta de Ben Noland.
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
Para aqueles que podem acabar aqui procurando a conversão oposta (de XMLGregorianCalendar
para Date
):
XMLGregorianCalendar xcal = <assume this is initialized>;
java.util.Date dt = xcal.toGregorianCalendar().getTime();
Aqui está um método para converter de um GregorianCalendar para XMLGregorianCalendar; Vou deixar a parte da conversão de um java.util.Date para o GregorianCalendar como um exercício para você:
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 :-)
Um exemplo de uma linha usando a biblioteca Joda-Time :
XMLGregorianCalendar xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(new DateTime().toGregorianCalendar());
Agradecemos a Nicolas Mommaerts por seu comentário na resposta aceita .
Apenas pensei em adicionar minha solução abaixo, pois as respostas acima não atendiam às minhas necessidades exatas. Meu esquema Xml exigia elementos separados de Data e Hora, não um único campo DateTime. O construtor XMLGregorianCalendar padrão usado acima gerará um campo DateTime
Observe alguns gothca's, como adicionar um ao mês (já que o java conta meses a partir de 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);
Espero que minha codificação aqui esteja correta; D Para torná-lo mais rápido, use a chamada feia getInstance () do GregorianCalendar em vez da chamada do construtor:
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()
é o equivalente de Calendar.getInstance()
. O Calendar.getInstance()
não pode torná-lo mais rápido, porque usa o mesmo new GregorianCalendar()
, mas antes também verifica o código do idioma padrão e pode criar um calendário japonês ou budista; portanto, para alguns usuários sortudos, será ClassCastException
!
Supondo que você esteja decodificando ou codificando xml e usando JAXB
, é possível substituir completamente a ligação dateTime e usar algo diferente de `XMLGregorianCalendar 'para todas as datas no esquema.
Dessa forma, você pode JAXB
fazer coisas repetitivas enquanto pode gastar tempo escrevendo códigos incríveis que agregam valor.
Exemplo para um jodatime DateTime
: (Fazer isso com o java.util.Date também funcionaria - mas com algumas limitações. Prefiro o jodatime e ele é copiado do meu código para que eu saiba que funciona ...)
<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>
E o conversor:
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);
}
}
Veja aqui: como substituir o XmlGregorianCalendar por Data?
Se você deseja apenas mapear para um instante com base no fuso horário + no registro de data e hora, e o fuso horário original não for realmente relevante, java.util.Date
provavelmente também será bom.
Confira este código: -
/* 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);
Você pode ver um exemplo completo aqui
ZonedDateTime
classe e novos métodos de conversão adicionados às classes herdadas. Detalhes nesta resposta por Ole VV