Estoy tratando de convertir una cadena con formato ISO 8601 a a java.util.Date
.
Encontré que el patrón yyyy-MM-dd'T'HH:mm:ssZ
cumple con ISO8601 si se usa con una configuración regional (comparar muestra).
Sin embargo, usando java.text.SimpleDateFormat
, no puedo convertir la cadena formateada correctamente 2010-01-01T12:00:00+01:00
. Tengo que convertirlo primero 2010-01-01T12:00:00+0100
, sin el colon.
Entonces, la solución actual es
SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.GERMANY);
String date = "2010-01-01T12:00:00+01:00".replaceAll("\\+0([0-9]){1}\\:00", "+0$100");
System.out.println(ISO8601DATEFORMAT.parse(date));
lo cual obviamente no es tan bueno. ¿Me estoy perdiendo algo o hay una solución mejor?
Responder
Gracias al comentario de JuanZe, encontré la magia de Joda-Time , también se describe aquí .
Entonces, la solución es
DateTimeFormatter parser2 = ISODateTimeFormat.dateTimeNoMillis();
String jtdate = "2010-01-01T12:00:00+01:00";
System.out.println(parser2.parseDateTime(jtdate));
O más simplemente, use el analizador predeterminado a través del constructor:
DateTime dt = new DateTime( "2010-01-01T12:00:00+01:00" ) ;
Para mí, esto es bueno.
Respuestas:
Desafortunadamente, los formatos de zona horaria disponibles para SimpleDateFormat (Java 6 y versiones anteriores) no son compatibles con ISO 8601 . SimpleDateFormat comprende cadenas de zona horaria como "GMT + 01: 00" o "+0100", esta última según RFC # 822 .
Incluso si Java 7 agregó soporte para descriptores de zona horaria de acuerdo con ISO 8601, SimpleDateFormat aún no puede analizar correctamente una cadena de fecha completa, ya que no tiene soporte para partes opcionales.
Reformatear su cadena de entrada usando regexp es ciertamente una posibilidad, pero las reglas de reemplazo no son tan simples como en su pregunta:
La solución más fácil es posiblemente usar el convertidor de tipo de datos en JAXB, ya que JAXB debe poder analizar la cadena de fecha ISO8601 de acuerdo con la especificación del esquema XML.
javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z")
le dará unCalendar
objeto y simplemente puede usar getTime () en él, si necesita unDate
objeto.Probablemente también podrías usar Joda-Time , pero no sé por qué deberías molestarte con eso.
fuente
La forma en que está bendecida por la documentación de Java 7 :
Puede encontrar más ejemplos en la sección Ejemplos en SimpleDateFormat javadoc .
UPD 13/02/2020: Hay una forma completamente nueva de hacer esto en Java 8
fuente
java.time
marco en Java 8, inspirado en Joda-Time , suplantando las problemáticas clases java.util.Date, .Calendar y SimpleDateFormat.string1
ystring2
no sabe cuál obtendrá?De acuerdo, esta pregunta ya está respondida, pero de todos modos dejaré mi respuesta. Podría ayudar a alguien.
He estado buscando una solución para Android (API 7).
javax.xml
no funcionarán en Android API 7.Terminé implementando esta clase simple. Cubre solo la forma más común de cadenas ISO 8601, pero esto debería ser suficiente en algunos casos (cuando esté seguro de que la entrada estará en este formato).
Nota de rendimiento: cada vez que instalo un nuevo SimpleDateFormat para evitar un error en Android 2.1. Si estás tan asombrado como yo, mira este acertijo . Para otros motores Java, puede almacenar en caché la instancia en un campo estático privado (usando ThreadLocal, para ser seguro para subprocesos).
fuente
s = s.substring(0, 22) + s.substring(23);
? No veo el punto en estojava.time
La API java.time (integrada en Java 8 y posterior) hace esto un poco más fácil.
Si sabe que la entrada está en UTC , como
Z
(para Zulu) al final, laInstant
clase puede analizar.Si su entrada puede ser otros valores de desplazamiento de UTC en lugar de UTC indicado por
Z
(Zulu) al final, use laOffsetDateTime
clase para analizar.Luego extraiga un
Instant
, y convierta a unjava.util.Date
llamandofrom
.fuente
LocalDateTime
yZoneId
yatZone
. Esta línea simple hará:java.util.Date date = Date.from( ZonedDateTime.parse( "2014-12-12T10:39:40Z" ).toInstant() );
Date.from(Instant.parse("2014-12-12T10:39:40Z" ));
es suficiente.OffsetDateTime
adicional, sería suficiente analizar ISO8601 (que no contiene información de zona horaria sino solo un desplazamiento).Instant
realice el análisis. Si bien no es suficiente para esta pregunta en particular, es una distinción importante que vale la pena señalar. Entonces agregué un segundo ejemplo de código. Vaya, acabo de notar que esta no es originalmente mi respuesta; Espero que Adam lo apruebe.La biblioteca Jackson-databind también tiene la clase ISO8601DateFormat que hace eso (implementación real en ISO8601Utils .
fuente
2015-08-11T13:10:00
. ConsigoString index out of range: 19
. Al mirar el código, parece que requiere que se especifiquen los milisegundos y la zona horaria. Esos deberían ser opcionales.[yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh:mm]]
. En otras palabras, los milisegundos son opcionales, pero la zona horaria es obligatoria.new DateTime("2015-08-11T13:10:00").toDate()
tl; dr
Usando java.time
El nuevo paquete java.time en Java 8 y posterior se inspiró en Joda-Time.
La
OffsetDateTime
clase representa un momento en la línea de tiempo con un desplazamiento desde UTC pero no una zona horaria.Las llamadas
toString
generan una cadena en formato estándar ISO 8601:Para ver el mismo valor a través de la lente de UTC, extraiga
Instant
o ajuste el desplazamiento de+01:00
a00:00
.…o…
Ajústelo a una zona horaria si lo desea. Una zona horaria es un historial de valores de compensación de UTC para una región, con un conjunto de reglas para manejar anomalías como el horario de verano (DST). Por lo tanto, aplique una zona horaria en lugar de un simple desplazamiento siempre que sea posible.
Sobre java.time
El marco java.time está integrado en Java 8 y versiones posteriores. Estas clases suplantar la vieja problemáticos heredados clases de fecha y hora como
java.util.Date
,Calendar
, ySimpleDateFormat
.El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .
Para obtener más información, consulte el Tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .
Puede intercambiar objetos java.time directamente con su base de datos. Utilice un controlador JDBC compatible con JDBC 4.2 o posterior. No hay necesidad de cadenas, no hay necesidad de
java.sql.*
clases.¿Dónde obtener las clases java.time?
El proyecto ThreeTen-Extra extiende java.time con clases adicionales. Este proyecto es un campo de pruebas para posibles adiciones futuras a java.time. Usted puede encontrar algunas clases útiles aquí, como
Interval
,YearWeek
,YearQuarter
, y más .fuente
Para Java versión 7
Puede seguir la documentación de Oracle: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
X: se utiliza para la zona horaria ISO 8601
fuente
La solución DatatypeConverter no funciona en todas las máquinas virtuales. Lo siguiente funciona para mí:
Descubrí que joda no funciona fuera de la caja (específicamente para el ejemplo que di arriba con la zona horaria en una fecha, que debería ser válida)
fuente
Creo que deberíamos usar
para la fecha
2010-01-01T12:00:00Z
fuente
A partir de Java 8, hay una forma completamente nueva oficialmente compatible de hacer esto:
fuente
Z
como desplazamiento, no necesitamos especificar esto explícitamente. JustoInstant i = Instant.parse(s);
. La cadena en la pregunta tenía+01:00
, en cuyo casoDateTimeFormatter.ISO_INSTANT
no funciona (al menos no en mi Java 11).ISO_OFFSET_DATE_TIME
para formatear fechas con desplazamientos, como+01:00
( docs.oracle.com/javase/8/docs/api/java/time/format/… )Otra forma muy simple de analizar las marcas de tiempo ISO8601 es usar
org.apache.commons.lang.time.DateUtils
:fuente
java.time
Tenga en cuenta que en Java 8, puede usar la clase java.time.ZonedDateTime y su
parse(CharSequence text)
método estático .fuente
Instant
yZonedDateTime
son apropiados aquí, noZonedDateTime
.La solución para Java 7+ está usando SimpleDateFormat:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);
Este código puede analizar el formato ISO8601 como:
2017-05-17T06:01:43.785Z
2017-05-13T02:58:21.391+01:00
Pero en Java6,
SimpleDateFormat
no entiende elX
carácter y arrojaráIllegalArgumentException: Unknown pattern character 'X'
Necesitamos normalizar la fecha ISO8601 al formato legible en Java 6 con
SimpleDateFormat
.Método anterior para reemplazar [
Z
con+0000
] o [+01:00
con+0100
] cuando se produce un error en Java 6 (puede detectar la versión de Java y reemplazar la declaración try / catch con if).fuente
Date
ySimpleDateFormat
están mal diseñadas, confusas y defectuosas. Ahora son heredados, suplantados por las clases java.time integradas en Java 8 y posteriores. Para Java 6 y Java 7, gran parte de la funcionalidad java.time se transfiere en el proyecto ThreeTen-Backport . Es mucho mejor agregar esa biblioteca a su aplicación que usar esas clases heredadas. Solución de una línea en java.time:OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" )
Me enfrenté al mismo problema y lo resolví con el siguiente código.
Anteriormente estaba usando
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());
Pero después encontré la causa principal de la excepción fue el
yyyy-MM-dd'T'HH:mm:ss.SSSZ
,Entonces solía
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
Funcionó bien para mí.
fuente
También puedes usar la siguiente clase:
Enlace al Java Doc - Jerarquía del paquete org.springframework.extensions.surf.maven.plugin.util
fuente
Java tiene una docena de formas diferentes de analizar una fecha y hora, como demuestran las excelentes respuestas aquí. ¡Pero de manera sorprendente, ninguna de las clases de tiempo de Java implementa completamente ISO 8601!
Con Java 8, recomendaría:
Eso manejará ejemplos tanto en UTC como con un desplazamiento, como "2017-09-13T10: 36: 40Z" o "2017-09-13T10: 36: 40 + 01: 00". Lo hará para la mayoría de los casos de uso.
Pero no manejará ejemplos como "2017-09-13T10: 36: 40 + 01", que es una fecha y hora ISO 8601 válida.
Tampoco manejará solo la fecha, por ejemplo, "2017-09-13".
Si tiene que manejarlos, sugeriría usar una expresión regular primero para oler la sintaxis.
Aquí hay una buena lista de ejemplos de ISO 8601 con muchos casos de esquina: https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/ I'm no conoce ninguna clase de Java que pueda hacer frente a todas ellas.
fuente
OffsetDateTime
hará y conceptualmente coincide con una fecha y hora con un desplazamiento mejor.OffsetDateTime
maneja los ejemplos con los que manejasZonedDateTime
. Creo que no maneja ninguno de los ejemplos queZonedDateTime
no lo hace. En ese sentido no es una mejora (pero tampoco peor). Lo siento, no estaba perfectamente claro.Apache Jackrabbit usa el formato ISO 8601 para las fechas persistentes, y hay una clase auxiliar para analizarlas:
org.apache.jackrabbit.util.ISO8601
Viene con jackrabbit-jcr-commons .
fuente
Como otros han mencionado, Android no tiene una buena manera de admitir el análisis / formateo de fechas ISO 8601 utilizando las clases incluidas en el SDK. He escrito este código varias veces, así que finalmente creé un Gist que incluye una clase DateUtils que admite el formato y el análisis de las fechas ISO 8601 y RFC 1123. The Gist también incluye un caso de prueba que muestra lo que admite.
https://gist.github.com/mraccola/702330625fad8eebe7d3
fuente
SimpleDateFormat para JAVA 1.7 tiene un patrón genial para el formato ISO 8601.
Clase SimpleDateFormat
Aquí esta lo que hice:
fuente
Z
en formato de cadena no es zona horaria ISO 8601, debe usarX
(XX
oXXX
) si desea zona horaria ISO 8601Hazlo asi:
Aquí está la salida:
Mié 19 oct 15:15:36 CST 2016
fuente
Usar cadena como
LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)
fuente
Me sorprende que ni una sola biblioteca de Java sea compatible con todos los formatos de fecha ISO 8601 según https://en.wikipedia.org/wiki/ISO_8601 . Joda DateTime era compatible con la mayoría de ellos, pero no con todos y, por lo tanto, agregué una lógica personalizada para manejarlos a todos. Aquí está mi implementación.
fuente
Una pequeña prueba que muestra cómo analizar una fecha en ISO8601 y que LocalDateTime no maneja los DST.
fuente
java.util.Date
,java.util.Calendar
yjava.text.SimpleDateFormat
ahora son heredadas , suplantadas por las clases java.time integradas en Java 8 y posteriores. Ver Tutorial de Oracle .LocalDateTime
y no maneja el horario de verano (DST) ya que no maneja una zona horaria en absoluto. Para eso necesitamosZonedDateTime
. ProponiendoDate
ySimpleDateFormat
es - en mi humilde opinión.Tenía una necesidad similar: necesitaba poder analizar cualquier fecha compatible con ISO8601 sin conocer el formato exacto de antemano, y quería una solución ligera que también funcionara en Android.
Cuando busqué en Google mis necesidades, me topé con esta pregunta y noté que AFAIU, ninguna respuesta se ajustaba completamente a mis necesidades. Así que desarrollé jISO8601 y lo presioné en Maven Central.
Solo agrega en ti
pom.xml
:y entonces estás listo para ir:
Espera que ayude.
fuente
Para formatear una fecha como esta, lo siguiente funcionó para mí en una aplicación basada en Java 6. Hay una
DateFormat
claseJacksonThymeleafISO8601DateFormat
en el proyecto de hoja de tomillo que inserta el colon faltante:https://github.com/thymeleaf/thymeleaf/blob/40d27f44df7b52eda47d1bc6f1b3012add6098b3/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java
Lo utilicé para la compatibilidad del formato de fecha ECMAScript.
fuente
Cortesía de la función base: @wrygiel.
Esta función puede convertir el formato ISO8601 a Java Date, que puede manejar los valores de desplazamiento. Según la definición de ISO 8601, el desplazamiento puede mencionarse en diferentes formatos.
Esta clase tiene métodos estáticos para convertir
Cadenas de muestra ISO8601
}
fuente
Esto pareció funcionar mejor para mí:
Necesitaba convertir a / para cadenas de fecha JavaScript a Java. Encontré que lo anterior funciona con la recomendación. Hubo algunos ejemplos usando SimpleDateFormat que estaban cerca pero no parecían ser el subconjunto recomendado por:
http://www.w3.org/TR/NOTE-datetime
y soportado por PLIST y JavaScript Strings y tal que es lo que necesitaba.
Esta parece ser la forma más común de cadena ISO8601, y un buen subconjunto.
Los ejemplos que dan son:
También tengo una versión rápida:
...
No lo he comparado, pero supongo que será bastante rápido. Parece funcionar. :)
fuente
Creo que lo que mucha gente quiere hacer es analizar cadenas de fechas JSON. Si viene a esta página, es muy probable que desee convertir una fecha JSON de JavaScript en una fecha Java.
Para mostrar cómo se ve una cadena de fecha JSON:
La cadena de fecha JSON es 2013-12-14T01: 55: 33.412Z.
Las fechas no están cubiertas por la especificación JSON por ejemplo, pero lo anterior es un formato ISO 8601 muy específico, mientras que ISO_8601 es mucho más grande y ese es un mero subconjunto, aunque muy importante.
Ver http://www.json.org Ver http://en.wikipedia.org/wiki/ISO_8601 Ver http://www.w3.org/TR/NOTE-datetime
Resulta que escribí un analizador JSON y un analizador PLIST que usan ISO-8601 pero no los mismos bits.
Escribí dos formas de hacer esto para mi proyecto. Un estándar, uno rápido.
Nuevamente, la cadena de fecha JSON es una implementación muy específica de ISO 8601 ...
(Publiqué el otro en la otra respuesta que debería funcionar para las fechas PLIST, que son un formato ISO 8601 diferente).
La fecha JSON es la siguiente:
Los archivos PLIST (ASCII no GNUNext) también usan ISO 8601 pero no milisegundos, así que ... no todas las fechas ISO-8601 son iguales. (Al menos aún no he encontrado uno que use milis y el analizador que he visto omite la zona horaria OMG).
Ahora para la versión rápida (puedes encontrarla en Boon).
Tenga en cuenta que Reflection.toCharArray usa inseguro si está disponible, pero por defecto es string.toCharArray si no.
(Puede sacarlo del ejemplo reemplazando Reflection.toCharArray (string) con string.toCharArray ()).
El isJsonDate se implementa de la siguiente manera:
De todos modos ... supongo que algunas personas que vienen aquí ... podrían estar buscando la cadena de fecha JSON y, aunque es una fecha ISO-8601, es muy específica y necesita un análisis muy específico.
Consulte https://github.com/RichardHightower/boon Boon tiene un analizador PLIST (ASCII) y un analizador JSON.
El analizador JSON es el analizador Java JSON más rápido que conozco.
Verificado independientemente por los muchachos de Gatling Performance.
https://github.com/gatling/json-parsers-benchmark
Tiene el analizador JSON más rápido para secuencias, lectores, bytes [], char [], CharSequence (StringBuilder, CharacterBuffer) y String.
Ver más puntos de referencia en:
https://github.com/RichardHightower/json-parsers-benchmark
fuente
Instant.parse( "2013-12-14T01:55:33.412Z" )