java - libreria - fecha de análisis simpledateformat con literal ''Z''
simpledateformat in java (12)
Estoy tratando de analizar una fecha que se ve así:
2010-04-05T17:16:00Z
Esta 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
Se analizará como un lunes 05 de abril a las 17:16:00 EDT 2010
SimpleDateFormat no puede analizar la cadena con estos patrones:
yyyy-MM-dd''T''HH:mm:ssz
yyyy-MM-dd''T''HH:mm:ssZ
Puedo establecer explícitamente el TimeZone para usar en SimpleDateFormat para obtener el resultado esperado, pero no creo que deba ser necesario. ¿Hay algo que este olvidando? ¿Hay un analizador de fechas alternativo?
tl; dr
Instant.parse ( "2010-04-05T17:16:00Z" )
Norma ISO 8601
Su cadena cumple con la norma ISO 8601 (de la cual el mencionado http://www.ietf.org/rfc/rfc3339.txt es un perfil).
Evita juDate
Las clases java.util.Date y .Calendar incluidas con Java son notoriamente problemáticas. Evítales.
En su lugar, utilice la biblioteca Joda-Time o el nuevo paquete java.time en Java 8. Ambos usan ISO 8601 como sus valores predeterminados para analizar y generar representaciones de cadena de valores de fecha y hora.
java.time
El marco java.time integrado en Java 8 y posterior suplanta las problemáticas antiguas clases java.util.Date/.Calendar. Las nuevas clases están inspiradas en el exitoso framework Joda-Time , diseñado como su sucesor, similar en concepto pero rediseñado. Definido por JSR 310 . Ampliado por el proyecto ThreeTen-Extra . Ver el Tutorial .
La clase Instant
en java.time representa un momento en la línea de tiempo en la zona horaria UTC .
La Z
al final de su cadena de entrada significa Zulu
que significa UTC
. Una clase de este tipo puede ser analizada directamente por la clase Instant
, sin necesidad de especificar un formateador.
String input = "2010-04-05T17:16:00Z";
Instant instant = Instant.parse ( input );
Volcado a la consola.
System.out.println ( "instant: " + instant );
instante: 2010-04-05T17: 16: 00Z
Desde allí, puede aplicar un huso horario ( ZoneId
) para ajustar este Instant
a un ZonedDateTime
. Búsqueda de desbordamiento de pila para discusión y ejemplos.
Si debe usar un objeto java.util.Date
, puede convertir 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.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ):
DateTime dateTime = new DateTime( "2010-04-05T17:16:00Z", timeZone );
Convertir a UTC.
DateTime dateTimeUtc = dateTime.withZone( DateTimeZone.UTC );
Convierta a java.util.Date si es necesario.
java.util.Date date = dateTime.toDate();
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.
En caso de que esté trabajando en un proyecto de Android , es posible que desee consultar la biblioteca de ThreeTenABP .
compile "com.jakewharton.threetenabp:threetenabp:${version}"
JSR-310 se incluyó en Java 8 como el paquete java.time. *. 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.
De acuerdo con la última fila en la tabla Patrones de fecha y hora de la API de Java 7
X Zona horaria ISO 8601 zona horaria -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 Apr 05 13:16:00 EDT 2010''
Desde java 8 simplemente use ZonedDateTime.parse("2010-04-05T17:16:00Z")
El proyecto restlet incluye una clase InternetDateFormat que puede analizar RFC 3339 fechas.
Sin embargo, es posible que desee reemplazar la ''Z'' final por "UTC" antes de analizarla.
En Java 8 use el DateTimeFormatter predefinido.ISO_DATE_TIME
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
ZonedDateTime result = ZonedDateTime.parse("2010-04-05T17:16:00Z", formatter);
Supongo que es la manera más fácil
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" de zona horaria general , ejemplos de los cuales son Pacific Standard Time; PST; GMT-08:00
Pacific Standard Time; PST; GMT-08:00
Pacific Standard Time; PST; GMT-08:00
.
Una ''Z'' indica que la zona horaria cumple con el estándar de zona horaria RFC 822 , por ejemplo, -0800
.
Creo que necesitas 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());
}
Java no analiza correctamente las fechas ISO.
Similar a la respuesta de McKenzie.
Solo arregla la 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
La ''X'' solo funciona si no hay segundos parciales: es decir, el patrón SimpleDateFormat de
"aaaa-MM-dd''T''HH: mm: ssX"
Analizará correctamente
"2008-01-31T00: 00: 00Z"
pero
"aaaa-MM-dd''T''HH: mm: ss.SX"
NO analizará
"2008-01-31T00: 00: 00.000Z"
Triste pero cierto, un date-time con segundos parciales no parece ser una fecha ISO válida: http://en.wikipedia.org/wiki/ISO_8601
La fecha en que realiza el análisis está en formato ISO8601.
En java 7, el patrón para leer y aplicar el sufijo de la zona horaria debe leer yyyy-MM-dd''T''HH:mm:ssX
La zona horaria debe ser algo así como "GMT + 00: 00" o 0000 para que el SimpleDateFormat pueda analizarla correctamente: puede reemplazar Z con esta construcción.
Proporciono otra respuesta que encontré por api-client-library
de 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í está la referencia 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 fuente de la clase DateTime
,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/main/java/com/google/api/client/util/DateTime.java
Pruebas de unidad 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