data de análise de formato simpled com o literal ‘Z’

Eu estou tentando analisar uma data que se parece com isso:

2010-04-05T17:16:00Z 

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

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

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

Será analisado como um Seg Abr 05 17:16:00 EDT 2010

SimpleDateFormat não consegue analisar a string com esses padrões:

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

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

No padrão, a inclusão de um componente de data e hora ‘z’ indica que o formato de fuso horário precisa estar em conformidade com o fuso horário geral “standard”, cujos exemplos são o Pacific Standard Time; PST; GMT-08:00 Pacific Standard Time; PST; GMT-08:00 Pacific Standard Time; PST; GMT-08:00 .

Um ‘Z’ indica que o fuso horário está em conformidade com o padrão de fuso horário do RFC 822 , 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()); } 

Java não analisa datas ISO corretamente.

Semelhante à resposta de McKenzie.

Apenas corrija 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 para ler e aplicar o sufixo de fuso horário deve ser: yyyy-MM-dd'T'HH:mm:ssX

tl; dr

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

Norma ISO 8601

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

Evite juDate

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

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

java.time

O framework java.time embutido no Java 8 e posterior suplanta as classs java.util.Date/.Calendar antigas problemáticas. As novas classs são inspiradas pelo altamente bem – sucedido framework Joda-Time , concebido como seu sucessor, similar em conceito, mas reprojetado. Definido pelo JSR 310 . Estendido pelo projeto ThreeTen-Extra . Veja o tutorial .

A class Instant em java.time representa um momento na linha do tempo no fuso horário UTC .

O Z no final da sua string de input significa Zulu que significa UTC . Essa string pode ser analisada diretamente pela class Instant , sem a necessidade de especificar um formatador.

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

Despeje 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 esse Instant em um ZonedDateTime . Pesquisa Stack Overflow para discussão e exemplos.

Se você precisar usar um object java.util.Date , poderá converter chamando os novos methods de conversão adicionados às classs 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 ); 

Converta para UTC.

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

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

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

De acordo com a última linha na tabela Padrões de data e hora da API do Java 7

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

Para o fuso horário ISO 8601, você deve usar X (-08 ou Z); XX (-0800 ou Z); e XXX (-08: 00 ou Z) para analisar seu “2010-04-05T17: 16: 00Z” é “aaaa-MM-dd’T’HH: mm: ssX” ou “aaaa-MM-dd ‘ T’HH: mm: ssXX “ou” aaaa-MM-dd’T’HH: mm: ssXXX “ deve funcionar.

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

irá imprimir corretamente ‘seg 05 de abril 13:16:00 EDT 2010’

O ‘X’ só funciona se os segundos parciais não estiverem presentes: ie SimpleDateFormat pattern of

“aaaa-MM-dd’T’HH: mm: ssX”

Irá analisar corretamente

“2008-01-31T00: 00: 00Z”

mas

“aaaa-MM-dd’T’HH: mm: ss.SX”

NÃO irá analisar

“2008-01-31T00: 00: 00.000Z”

Triste mas verdadeiro, uma data-hora com segundos parciais não parece ser uma data 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 replace Z por essa construção.

O projeto de restauração inclui uma class InternetDateFormat que pode analisar as datas RFC 3339.

Restlet InternetDateFormat

Porém, você pode querer apenas replace o trecho “Z” por “UTC” antes de analisá-lo.

Eu forneço outra resposta que encontrei por api-client-library by 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á a referência da API,
http://www.google.com/adwords

Código fonte da class DateTime ,
http://www.google.com/intl/pt-BR/google

Testes de unidade DateTime ,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/test/java/com/google/api/client/util/DateTimeTest.java#L121

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

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

Caso você esteja trabalhando em um projeto Android , talvez queira fazer o checkout da biblioteca ThreeTenABP .

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

O JSR-310 foi incluído no Java 8 como o pacote java.time. *. É uma substituição completa para as APIs de data e calendar em dificuldades tanto no Java quanto no Android. O JSR-310 foi devolvido para o Java 6 por seu criador, Stephen Colebourne, do qual esta biblioteca é adaptada.

No Java 8, use o DateTimeFormatter.ISO_DATE_TIME predefinido

  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 o java 8 é só usar ZonedDateTime.parse("2010-04-05T17:16:00Z")