java.util.Date para XMLGregorianCalendar

601

Não existe uma maneira conveniente de passar de um java.util.Date para um XMLGregorianCalendar?

Mac
fonte
FYI: Essas duas classes terríveis foram substituídas anos atrás pelas classes java.time definidas no JSR 310. Consulte a ZonedDateTimeclasse e novos métodos de conversão adicionados às classes herdadas. Detalhes nesta resposta por Ole VV
Basil Bourque

Respostas:

36

Gostaria de dar um passo atrás e dar uma olhada moderna nesta questão de 10 anos de idade. As aulas mencionadas Datee XMLGregorianCalendarsão antigas agora. Desafio o uso deles e ofereço alternativas.

  • Datesempre foi mal projetado e tem mais de 20 anos. Isso é simples: não use.
  • XMLGregorianCalendartambé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:00ou 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.

Nenhuma conversão necessária

Para muitos propósitos (a maioria?), A substituição moderna de a Dateserá 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 XMLGregorianCalendarstrings acima. Como muitos de vocês sabem, vem de Instant.toStringser 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, XMLGregorianCalendare outras classes (em alguns casos, fazer conversões necessidade, porém, eu estou mostrando-lhe um par na próxima seção) .

Controlando o deslocamento

Nem a Datenem in Instantpossui 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 zonecomo ZoneId.systemDefault().

E se eu precisar absolutamente de um XMLGregorianCalendar?

Existem mais maneiras de converter Instantpara XMLGregorianCalendar. Vou apresentar um casal, cada um com seus prós e contras. Primeiro, assim como um XMLGregorianCalendarproduz 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.

E se tivermos um encontro?

Se você obteve um Dateobjeto 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 OffsetDateTimeda mesma maneira que acima.

Se você tem um antiquado Datee absolutamente precisa de um antiquado XMLGregorianCalendar, basta usar a resposta de Ben Noland.

Ligações

Ole VV
fonte
1034
GregorianCalendar c = new GregorianCalendar();
c.setTime(yourDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
Ben Noland
fonte
5
É salvo manter o getInstance () como uma variável estática em alguma classe de conversor? Eu tentei procurar no JavaDoc, mas não consegui encontrar nada. Meio difícil saber se haverá problemas no uso simultâneo?
Martin
36
Se você estiver disposto a usar JodaTime você pode fazer isso em uma linha: DatatypeFactory.newInstance () newXMLGregorianCalendar. (New DateTime () toGregorianCalendar ().)
Nicolas Mommaerts
3
XMLGregorianCalendar date2 = DatatypeFactory.newInstance (). NewXMLGregorianCalendar (novo calendário gregoriano (AAAA, MM, DD));
Junchen Liu
3
Esteja ciente de que o Calendário não é seguro para threads e, portanto, também não é GregorianCalender. Veja também stackoverflow.com/questions/12131324/…
questionaire
. Uma versão de linha - DatatypeFactory.newInstance () newXMLGregorianCalendar (novo GregorianCalendar () {{setTime (yourDate);}})
Alex Vayda
205

Para aqueles que podem acabar aqui procurando a conversão oposta (de XMLGregorianCalendarpara Date):

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

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 :-)

sasuke
fonte
6
Esta solução a converter GregorianCalendar para XMLGregorianCalendar e não o que é indicado na questão
ftrujillo
22

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 .

Chris Knight
fonte
12

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);
quilo
fonte
10

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);
   }

}
Daniel K.
fonte
14
-1 para usar .getInstance (). 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!
kan
6

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 JAXBfazer 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.Dateprovavelmente também será bom.

KarlP
fonte
0

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

Akash
fonte
Acho que essa resposta não fornece nada de novo. Talvez você possa editar a resposta anterior em vez de postar outra quase a mesma coisa.
winter
1
Como fazer um dateFormat para XMLGregorianCalendar?
Panadol Chong