2010-04-05 25 views
61

Estoy tratando de analizar una fecha en la que se ve así:SimpleDateFormat fecha de análisis con 'Z' literal

2010-04-05T17:16:00Z 

Ésta es una fecha válida por http://www.ietf.org/rfc/rfc3339.txt. El literal 'Z' implica que UTC es el punto de referencia preferido para el tiempo especificado. "

Si trato de analizarlo usando SimpleDateFormat y este patrón:

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

será analizado como un Dom Mar 05 17:16:00 EDT 2010

SimpleDateFormat no es capaz de analizar la cadena con estos patrones:

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

puedo establecer explícitamente la zona horaria a usar en la SimpleDateFormat para obtener el resultado esperado, pero no creo que debería ser necesario. ¿Hay algo que este olvidando? ¿Hay un analizador de fechas alternativo?

+11

El sufijo 'Z' en el sello de tiempo no debe confundirse con Z o z en el patrón. En java 7 puede analizar un sufijo ISO8601 con SimpleDateFormat usando la letra de patrón 'X'. –

+0

FYI, las viejas clases problemáticas de fecha y hora como 'SimpleTextFormat' ahora son [legacy] (https://en.wikipedia.org/wiki/Legacy_system), suplantadas por [java.time] (https: // docs .oracle.com/javase/8/docs/api/java/time/package-summary.html) clases. Consulte [Tutorial de Oracle] (https://docs.oracle.com/javase/tutorial/datetime/TOC.html). –

Respuesta

28

En el patrón, la inclusión de un componente de fecha y hora 'z' indica que el formato de zona horaria debe ajustarse al "estándar" General time zone, ejemplos de los cuales son Pacific Standard Time; PST; GMT-08:00.

A 'Z' indica que la zona horaria cumple con el estándar RFC 822 time zone, p. -0800.

Creo que se necesita un 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()); 
} 
+0

sí, entiendo eso. Las permutaciones z/Z eran solo yo viendo si algo se quedaría. Todavía queda que mi fecha sea válida y debería haber un patrón válido para analizarla. – DanInDC

+0

Estaba luchando por recordar la clase 'DatatypeConverter' que un colega me mostró hace poco. –

+0

Consulte también http://stackoverflow.com/questions/2201925/converting-iso8601-compliant-string-to-java-util-date respuesta anterior –

3

La zona horaria debe ser algo así como "GMT + 00: 00" o 0000 para poder analizarla correctamente con SimpleDateFormat; puede reemplazar Z con esta construcción.

2

El proyecto incluye una clase Restlet InternetDateFormat que puede analizar RFC 3339 fechas.

Restlet InternetDateFormat

Sin embargo, es posible que quieran sustituir la 'Z' se arrastra con "UTC" antes de analizarlo.

+0

Restlet InternetDateFormat funcionó bien para mí – emmby

46

Java no analiza correctamente las fechas ISO.

Similar a la respuesta de McKenzie.

Simplemente arregle el Z antes de analizar.

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 
+0

¡Qué lástima! Gracias por la sugerencia –

+17

Java 7 añadió la letra de patrón X para analizar las fechas ISO. –

+0

@Dave, gracias por la actualización! – Alex

25

La fecha está analizando está en formato ISO8601.

en Java 7 el patrón de leer y aplicar el sufijo zona horaria debe leer yyyy-MM-dd'T'HH:mm:ssX

+4

Esta debería haber sido la respuesta correcta en lugar de la respuesta aceptada. –

+0

Además, si desea analizar los minutos en la zona horaria, simplemente agregue una segunda o tercera 'X':' aaaa-MM-dd'T'HH: mm: ssXX' o 'aaaa-MM-dd'T'HH : mm: ssXXX'. Para obtener más información, consulte [SimpleDateFormat - Zona horaria ISO 8601] (https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html#iso8601timezone). – mateuscb

17

tl; dr

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

ISO 8601 Estándar

la cadena cumple con la ISO 8601 estándar (de los cuales el mencionado RFC 3339 es un perfil).

Evitar j.u.Date

Las clases java.util.Date y .calendar incluido con Java son notoriamente molesto. Evítales.

En su lugar, utilice la biblioteca Joda-Time o el nuevo paquete java.time en Java 8. Ambos utilizan ISO 8601 como valores predeterminados para analizar y generar representaciones de cadena de valores de fecha y hora.

java.time

El marco java.time incorporado en Java 8 y posterior suplanta las viejas clases java.util.Date/.Calendar problemáticos. Las nuevas clases están inspiradas en el exitoso marco Joda-Time, diseñado como su sucesor, similar en concepto pero rediseñado. Definido por JSR 310. Ampliado por el proyecto ThreeTen-Extra. Vea el Tutorial.

La clase Instant en java.time representa un momento en la línea de tiempo en UTC zona horaria.

El Z al final de su cadena de entrada significa Zulu que significa UTC. Dicha cadena se puede analizar directamente mediante la clase Instant, sin necesidad de especificar un formateador.

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

Volcar a la consola.

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

instantánea: 2010-04-05T17: 16: 00Z

Desde allí se puede aplicar una zona horaria (ZoneId) para ajustar esta Instant en un ZonedDateTime. Búsqueda de desbordamiento de pila para discusión y ejemplos.

Si debe usar un objeto java.util.Date, puede realizar la conversión llamando a los nuevos métodos de conversión agregados a las clases antiguas, como el método estático java.util.Date.from(Instant).

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

Joda-Time

Ejemplo en Joda-Time 2.5.

Convertir a UTC.

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

Convierta a un java.util.Date si es necesario.

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

Tenga en cuenta este artículo de Stephen Colebourne: [Por qué JSR-310 no es Joda-Time] (http://blog.joda.org/2009/11/why-jsr-310-isn-joda-time_4941.html) – JJD

5

La 'X' sólo funciona si segundo parciales no están presentes: es decir, patrón SimpleDateFormat de

"aaaa-MM-dd'T'HH: mm: SSX"

analizará correctamente

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

pero

"aaaa-MM-dd'T'HH: m m: ss.SX"

no va a analizar

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

triste pero cierto, una de fecha y hora con el segundo parcial no parece que haya una válida fecha ISO: http://en.wikipedia.org/wiki/ISO_8601

+2

Esto es terriblemente molesto. –

+0

Cita de la página wiki referenciada: "Se pueden agregar fracciones decimales a cualquiera de los tres elementos de tiempo. [...] No hay límite en el número de decimales para la fracción decimal. Sin embargo, el número de decimales debe ser acordado por las partes que se comunican." La" Z "es una noción independiente para las zonas horarias. Por lo tanto, los segundos parciales SON fechas ISO válidas Sería bueno analizar. (Tal vez no es un" Formato de fecha simple "?)) – MGM

2

proporciono otra respuesta que he encontrado por api-client-library por 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(); 
} 

guía de instalación,
https://developers.google.com/api-client-library/java/google-api-java-client/setup#download

Aquí es referencia de la API,
https://developers.google.com/api-client-library/java/google-http-java-client/reference/1.20.0/com/google/api/client/util/DateTime

El código fuente de DateTime clase,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/main/java/com/google/api/client/util/DateTime.java

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

2

Con respecto a JSR-310 otro proyecto de interés podría ser threetenbp.

JSR-310 proporciona una nueva biblioteca de fecha y hora para Java SE 8. Este proyecto es el backport a Java SE 6 y 7.

Si estás trabajando en un proyecto Android es posible que desee comprobar el ThreeTenABP library.

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

JSR-310 se incluyó en Java 8 como el java.time. * Paquete. Es un reemplazo completo de las API de fecha y calendario en problemas tanto en Java como en Android. JSR-310 fue transferido a Java 6 por su creador, Stephen Colebourne, del cual se adapta esta biblioteca.

7

Según última fila en la Date and Time Patterns tabla de la Java 7 API

X Tiempo zona ISO 8601 tiempo zona -08; -0800; -08: 00

Para la zona horaria ISO 8601 debe usar X (-08 o Z); XX (-0800 o Z); y XXX (-08: 00 o Z) así que para analizar su "2010-04-05T17: 16: 00Z" es "aaaa-MM-dd'T'HH: mm: ssX" o "aaaa-MM- dd'T'HH: mm: ssXX "o" aaaa-MM-dd'T'HH: mm: ssXXX " debería 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")); 

imprimirá correctamente 'Lun Abr 05 13:16:00 EDT 2010'

+0

Esto debería ser la respuesta aceptada, porque muestra cómo analizar la cadena de fecha usando SimpleDateFormat como la pregunta formulada. – davidgyoung

0

Bajo Java 8 uso del DateTimeFormatter.ISO_DATE_TIME predefinido

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

supongo que es la forma más fácil

0

Desde java 8 solo use ZonedDateTime.parse("2010-04-05T17:16:00Z")

Cuestiones relacionadas