Pergunta

Esta pergunta já tem uma resposta aqui:

Estou tentando analisar uma data que se parece com o seguinte:

2010-04-05T17:16:00Z

Esta é uma data válida por http://www.ietf.org/rfc/rfc3339.txt. O 'Z' literal "implica que o UTC é o ponto de referência preferido para o tempo especificado".

Se eu tentar analisá -lo usando o SimpleDateFormat e esse padrão:

yyyy-MM-dd'T'HH:mm:ss

Será analisado como seg 05 de abril 17:16:00 EDT 2010

SimpleDateFormat é incapaz de analisar a string com estes padrões:

yyyy-MM-dd'T'HH:mm:ssz
yyyy-MM-dd'T'HH:mm:ssZ

Posso definir explicitamente o fuso horário para usar no SimpleDateFormat para obter a saída esperada, mas não acho que isso seja necessário. Há algo que estou perdendo? Existe um analisador alternativo de data?

Foi útil?

Solução

No padrão, a inclusão de um componente de data de data 'Z' indica que o formato do fuso horário precisa estar em conformidade com o Fuso horário geral "padrão", cujos exemplos são Pacific Standard Time; PST; GMT-08:00.

A 'z' indica que o fuso horário está em conformidade com o RFC 822 fuso horário padrão, por exemplo -0800.

Eu acho que você precisa de um datatypeConverter ...

@Test
public void testTimezoneIsGreenwichMeanTime() throws ParseException {
    final Calendar calendar = javax.xml.bind.DatatypeConverter.parseDateTime("2010-04-05T17:16:00Z");
    TestCase.assertEquals("gotten timezone", "GMT+00:00", calendar.getTimeZone().getID());
}

Outras dicas

O Java não analisa as datas ISO corretamente.

Semelhante à resposta de McKenzie.

Basta consertar o Z antes de analisar.

Código

String string = "2013-03-05T18:05:05.000Z";
String defaultTimezone = TimeZone.getDefault().getID();
Date date = (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).parse(string.replaceAll("Z$", "+0000"));

System.out.println("string: " + string);
System.out.println("defaultTimezone: " + defaultTimezone);
System.out.println("date: " + (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).format(date));

Resultado

string: 2013-03-05T18:05:05.000Z
defaultTimezone: America/New_York
date: 2013-03-05T13:05:05.000-0500

A data em que você está analisando está no formato ISO8601.

Em Java 7, o padrão de ler e aplicar o sufixo do fuso horário deve ler yyyy-MM-dd'T'HH:mm:ssX

tl; dr

Instant.parse ( "2010-04-05T17:16:00Z" )

ISO 8601 padrão

Sua string está em conformidade com o ISO 8601 padrão (do qual o mencionado RFC 3339 é um perfil).

Evite Judate

As classes Java.util.Date e .Calendar, empacotadas com Java, são notoriamente problemáticas. Evite-os.

Em vez disso, use o Joda-Time Biblioteca ou o novo pacote Java.Time em Java 8. Ambos usam a ISO 8601 como padrões para analisar e gerar representações de string de valores de data-hora.

Java.Time

o Java.Time Framework incorporado ao Java 8 e depois suplanta o problemático antigo java.util.date/.Calendar Classes. As novas classes são inspiradas pelo sucesso Joda-Time Framework, destinado a seu sucessor, semelhante em conceito, mas re-arquitetado. Definido por JSR 310. Estendido pelo Threeten-Extra projeto. Veja o Tutorial.

o Instant A classe em Java.Time representa um momento na linha do tempo em UTC fuso horário.

o Z no final da sua sequência de entrada significa Zulu que significa UTC. Essa string pode ser analisada diretamente pelo Instant classe, sem necessidade de especificar um formatador.

String input = "2010-04-05T17:16:00Z";
Instant instant = Instant.parse ( input );

Despejar para consolar.

System.out.println ( "instant: " + instant );

Instante: 2010-04-05T17: 16: 00Z

A partir daí, você pode aplicar um fuso horário (ZoneId) para ajustar isso Instant dentro de ZonedDateTime. Pesquise pilha de transbordamento para discussão e exemplos.

Se você deve usar um java.util.Date Objeto, você pode converter chamando os novos métodos de conversão adicionados às classes antigas, como o método estático java.util.Date.from( Instant ).

java.util.Date date = java.util.Date.from( instant );

Joda-Time

Exemplo no Joda-Time 2.5.

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ):
DateTime dateTime = new DateTime( "2010-04-05T17:16:00Z", timeZone );

Converter para UTC.

DateTime dateTimeUtc = dateTime.withZone( DateTimeZone.UTC );

Converta em um java.util.Date, se necessário.

java.util.Date date = dateTime.toDate();

De acordo com a última linha no Padrões de data e hora Tabela do Java 7 API

X Fuso horário ISO 8601 fuso horário -08; -0800; -08: 00

Para o fuso horário da ISO 8601, você deve usar:

  • X para (-08 ou z),
  • Xx para (-0800 ou z),
  • Xxx para (-08: 00 ou z);

Então, para analisar o seu "2010-04-05T17: 16: 00Z", você pode usar qualquer um "yyyy-mm-dd't'hh: mm: ssx" ou "yyyy-mm-dd't'hh: mm: ssxx" ou "yyyy-mm-dd't'hh: mm: ssxxx" .

    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX").parse("2010-04-05T17:16:00Z"));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXX").parse("2010-04-05T17:16:00Z"));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").parse("2010-04-05T17:16:00Z"));

Imprimirá corretamente 'Seg 05 13:16:00 EDT 2010'

O 'X' só funciona se não estiverem segundos parciais: ou seja, padrão simplificado de formação de

"Aaaaaa-mm-dd't'hh: mm: ssx"

Irá analisar corretamente

"2008-01-31T00: 00: 00Z"

mas

"Aaaaaa-mm-dd't'hh: mm: ss.sx"

Não vai analisar

"2008-01-31T00: 00: 00.000Z"

Triste, mas é verdade, um encontro com segundos parciais não parece ser uma data de ISO válida: http://en.wikipedia.org/wiki/iso_8601

O fuso horário deve ser algo como "GMT+00: 00" ou 0000 para ser analisado corretamente pelo SimpleDateFormat - você pode substituir Z por esta construção.

O projeto RestLet inclui uma classe InternetDateFormat que pode analisar as datas RFC 3339.

RESTLETLET DO INTERNETDATEFORMAT

No entanto, você pode apenas substituir o 'Z' à direita pelo "UTC" antes de analisá -lo.

Eu forneço outra resposta que encontrei por api-client-library pelo Google

try {
    DateTime dateTime = DateTime.parseRfc3339(date);
    dateTime = new DateTime(new Date(dateTime.getValue()), TimeZone.getDefault());
    long timestamp = dateTime.getValue();  // get date in timestamp
    int timeZone = dateTime.getTimeZoneShift();  // get timezone offset
} catch (NumberFormatException e) {
    e.printStackTrace();
}

Guia de instalação,
https://developers.google.com/api-client-library/java/google-api-java-client/setup#download

Aqui está referência da API,
https://developers.google.com/api-client-library/java/google-http-java-client/reference/1.20.0/com/google/api/client/util/datetime

Código -fonte de DateTime Classe,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/main/java/com/google/api/client/util/datetime.java

DateTime testes de unidade,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/test/java/com/google/api/client/util/datetetest.java#l121

Com relação ao JSR-310, outro projeto de interesse pode ser Threetenbp.

O JSR-310 fornece uma nova biblioteca de data e hora para Java SE 8. Este projeto é o backport para Java SE 6 e 7.

Caso você esteja trabalhando em um Android Projeto que você pode querer verificar o Biblioteca Threetenabp.

compile "com.jakewharton.threetenabp:threetenabp:${version}"

O JSR-310 foi incluído no Java 8 como o pacote Java.Time.*. É um substituto completo para a data doente e as APIs do calendário em Java e Android. O JSR-310 foi apoiado para o Java 6 por seu criador, Stephen Colebourne, da qual esta biblioteca está adaptada.

Sob Java 8, use o DateTimeFormatter predefinido.iso_date_time

 DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
 ZonedDateTime result = ZonedDateTime.parse("2010-04-05T17:16:00Z", formatter);

Eu acho que é a maneira mais fácil

Desde que Java 8 apenas use ZonedDateTime.parse("2010-04-05T17:16:00Z")

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top