parse - Conversión de cadenas compatibles con ISO 8601 a java.util.Date
string to date java 8 (25)
java.time
Tenga en cuenta que en Java 8, puede usar la clase java.time.ZonedDateTime y su método de parse(CharSequence text)
estático parse(CharSequence text)
.
Estoy tratando de convertir una cadena con formato ISO 8601 a una fecha java.util.Date
.
Encontré que el patrón yyyy-MM-dd''T''HH:mm:ssZ
con la norma ISO8601 si se usa con una configuración regional (muestra de comparación).
Sin embargo, al usar java.text.SimpleDateFormat
, no puedo convertir el String correctamente formateado 2010-01-01T12:00:00+01:00
. Tengo que convertirlo primero a 2010-01-01T12:00:00+0100
, sin los dos puntos.
Por lo tanto, 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));
que 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 por defecto a través del constructor:
DateTime dt = new DateTime( "2010-01-01T12:00:00+01:00" ) ;
Para mí, esto es bueno.
tl; dr
OffsetDateTime.parse ( "2010-01-01T12:00:00+01:00" )
Usando java.time
El nuevo paquete java.time en Java 8 y versiones posteriores se inspiró en Joda-Time.
La clase OffsetDateTime
representa un momento en la línea de tiempo con un offset-from-UTC pero no una zona horaria.
OffsetDateTime odt = OffsetDateTime.parse ( "2010-01-01T12:00:00+01:00" );
La llamada a toString
genera una cadena en formato estándar ISO 8601:
2010-01-01T12: 00 + 01: 00
Para ver el mismo valor a través de la lente de UTC, extraiga un Instant
o ajuste la compensación de +01:00
a 00:00
.
Instant instant = odt.toInstant();
…o…
OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC );
Ajuste en una zona horaria si lo desea. Una zona horaria es un historial de valores de offset-from-UTC para una región, con un conjunto de reglas para el manejo de anomalías, como el horario de verano (DST). Así que aplique una zona horaria en lugar de un simple desplazamiento cuando sea posible.
ZonedDateTime zonedDateTimeMontréal = odt.atZoneSameInstant( ZoneId.of( "America/Montreal" ) );
Acerca de java.time
El marco java.time está integrado en Java 8 y java.time posteriores. Estas clases sustituyen a las antiguas y problemáticas clases de fecha y hora como java.util.Date
, Calendar
y SimpleDateFormat
.
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 busca para 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 se necesitan cadenas, no se necesitan clases java.sql.*
.
¿Dónde obtener las clases java.time?
- Java SE 8 , Java SE 9 , Java SE 10 y posteriores
- Incorporado.
- Parte de la API de Java estándar con una implementación en paquete.
- Java 9 agrega algunas características menores y correcciones.
- Java SE 6 y Java SE 7
- Gran parte de la funcionalidad de java.time está respaldada a Java 6 y 7 en ThreeTen-Backport .
- Android
- Versiones posteriores de las implementaciones de paquetes de Android de las clases java.time.
- Para Android anterior (<26), el proyecto ThreeTenABP adapta ThreeTen-Backport (mencionado anteriormente). Vea Cómo usar ThreeTenABP… .
El proyecto ThreeTen-Extra extiende java.time con clases adicionales. Este proyecto es un terreno de prueba para posibles adiciones futuras a java.time. Puede encontrar algunas clases útiles aquí como Interval
, YearWeek
, YearQuarter
, y more .
java.time
La API java.time (incorporada en Java 8 y posterior), hace esto un poco más fácil.
Si sabe que la entrada está en UTC , como la Z
(para Zulu) al final, la clase Instant
puede analizar.
java.util.Date date = Date.from( Instant.parse( "2014-12-12T10:39:40Z" ));
Si su entrada puede ser otro valor de offset-from-UTC lugar de UTC indicado por la Z
(Zulu) en el final, use la clase OffsetDateTime
para analizar.
OffsetDateTime odt = OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" );
Luego extraiga un Instant
y conviértalo a java.util.Date
llamando from
.
Instant instant = odt.toInstant(); // Instant is always in UTC.
java.util.Date date = java.util.Date.from( instant );
Bien, esta pregunta ya está contestada, pero voy a dejar mi respuesta de todos modos. Podría ayudar a alguien.
He estado buscando una solución para Android (API 7).
- Joda estaba fuera de discusión: es enorme y sufre una lenta inicialización. También parecía un gran exceso para ese propósito particular.
- Las respuestas relacionadas con
javax.xml
no funcionarán en la API 7 de Android.
Terminé implementando esta clase simple. Cubre solo la forma más común de las cadenas ISO 8601, pero esto debería ser suficiente en algunos casos (cuando esté bastante seguro de que la entrada estará en este formato).
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
/**
* Helper class for handling a most common subset of ISO 8601 strings
* (in the following format: "2008-03-01T13:00:00+01:00"). It supports
* parsing the "Z" timezone, but many other less-used features are
* missing.
*/
public final class ISO8601 {
/** Transform Calendar to ISO 8601 string. */
public static String fromCalendar(final Calendar calendar) {
Date date = calendar.getTime();
String formatted = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ssZ")
.format(date);
return formatted.substring(0, 22) + ":" + formatted.substring(22);
}
/** Get current date and time formatted as ISO 8601 string. */
public static String now() {
return fromCalendar(GregorianCalendar.getInstance());
}
/** Transform ISO 8601 string to Calendar. */
public static Calendar toCalendar(final String iso8601string)
throws ParseException {
Calendar calendar = GregorianCalendar.getInstance();
String s = iso8601string.replace("Z", "+00:00");
try {
s = s.substring(0, 22) + s.substring(23); // to get rid of the ":"
} catch (IndexOutOfBoundsException e) {
throw new ParseException("Invalid length", 0);
}
Date date = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ssZ").parse(s);
calendar.setTime(date);
return calendar;
}
}
Nota de rendimiento: instalo el nuevo SimpleDateFormat cada vez como un medio para evitar un error en Android 2.1. Si estás tan asombrado como yo, ve este enigma . Para otros motores Java, puede almacenar en caché la instancia en un campo estático privado (usando ThreadLocal, para estar seguro para subprocesos).
Como han mencionado otros, 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 formateo y análisis de fechas ISO 8601 y RFC 1123. The Gist también incluye un caso de prueba que muestra lo que admite.
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 compensación. Según la definición de ISO 8601, el desplazamiento puede mencionarse en diferentes formatos.
±[hh]:[mm]
±[hh][mm]
±[hh]
Eg: "18:30Z", "22:30+04", "1130-0700", and "15:00-03:30" all mean the same time. - 06:30PM UTC
Esta clase tiene métodos estáticos para convertir
- Cadena ISO8601 al objeto Fecha (Zona horaria local)
- Fecha a la cadena ISO8601
- El horario de verano se calcula automáticamente
Cuerdas de muestra ISO8601
/* "2013-06-25T14:00:00Z";
"2013-06-25T140000Z";
"2013-06-25T14:00:00+04";
"2013-06-25T14:00:00+0400";
"2013-06-25T140000+0400";
"2013-06-25T14:00:00-04";
"2013-06-25T14:00:00-0400";
"2013-06-25T140000-0400";*/
public class ISO8601DateFormatter {
private static final DateFormat DATE_FORMAT_1 = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ssZ");
private static final DateFormat DATE_FORMAT_2 = new SimpleDateFormat("yyyy-MM-dd''T''HHmmssZ");
private static final String UTC_PLUS = "+";
private static final String UTC_MINUS = "-";
public static Date toDate(String iso8601string) throws ParseException {
iso8601string = iso8601string.trim();
if(iso8601string.toUpperCase().indexOf("Z")>0){
iso8601string = iso8601string.toUpperCase().replace("Z", "+0000");
}else if(((iso8601string.indexOf(UTC_PLUS))>0)){
iso8601string = replaceColon(iso8601string, iso8601string.indexOf(UTC_PLUS));
iso8601string = appendZeros(iso8601string, iso8601string.indexOf(UTC_PLUS), UTC_PLUS);
}else if(((iso8601string.indexOf(UTC_MINUS))>0)){
iso8601string = replaceColon(iso8601string, iso8601string.indexOf(UTC_MINUS));
iso8601string = appendZeros(iso8601string, iso8601string.indexOf(UTC_MINUS), UTC_MINUS);
}
Date date = null;
if(iso8601string.contains(":"))
date = DATE_FORMAT_1.parse(iso8601string);
else{
date = DATE_FORMAT_2.parse(iso8601string);
}
return date;
}
public static String toISO8601String(Date date){
return DATE_FORMAT_1.format(date);
}
private static String replaceColon(String sourceStr, int offsetIndex){
if(sourceStr.substring(offsetIndex).contains(":"))
return sourceStr.substring(0, offsetIndex) + sourceStr.substring(offsetIndex).replace(":", "");
return sourceStr;
}
private static String appendZeros(String sourceStr, int offsetIndex, String offsetChar){
if((sourceStr.length()-1)-sourceStr.indexOf(offsetChar,offsetIndex)<=2)
return sourceStr + "00";
return sourceStr;
}
}
Creo que deberíamos usar
DateFormat format = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss''Z''")
para la fecha 2010-01-01T12:00:00Z
Desafortunadamente, los formatos de zona horaria disponibles para SimpleDateFormat (Java 6 y SimpleDateFormat anteriores) no son compatibles con ISO 8601 . SimpleDateFormat entiende las cadenas de zona horaria como "GMT + 01: 00" o "+0100", esta última de acuerdo con RFC # 822 .
Incluso si Java 7 agregó soporte para los descriptores de zona horaria según ISO 8601, SimpleDateFormat aún no puede analizar correctamente una cadena de fecha completa, ya que no tiene soporte para partes opcionales.
Volver a formatear la cadena de entrada usando regexp es ciertamente una posibilidad, pero las reglas de reemplazo no son tan simples como en tu pregunta:
- Algunas zonas horarias no son horas completas fuera de UTC , por lo que la cadena no termina necesariamente con ": 00".
- ISO8601 permite solo la cantidad de horas que se incluirán en la zona horaria, por lo que "+01" es equivalente a "+01: 00"
- ISO8601 permite el uso de "Z" para indicar UTC en lugar de "+00: 00".
La solución más fácil es posiblemente utilizar 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á un objeto de Calendar
y simplemente puede usar getTime (), si necesita un objeto Date
.
Probablemente podrías usar Joda-Time también, pero no sé por qué deberías preocuparte por eso.
Esto pareció funcionar mejor para mí:
public static Date fromISO8601_( String string ) {
try {
return new SimpleDateFormat ( "yyyy-MM-dd''T''HH:mm:ssXXX").parse ( string );
} catch ( ParseException e ) {
return Exceptions.handle (Date.class, "Not a valid ISO8601", e);
}
}
Necesitaba convertir a / fro cadenas de fecha de JavaScript a Java. He encontrado los trabajos anteriores con la recomendación. Hubo algunos ejemplos utilizando SimpleDateFormat que estaban cerca, pero no parecían ser el subconjunto como lo recomendó:
http://www.w3.org/TR/NOTE-datetime
y soportado por PLIST y JavaScript Strings y eso es lo que necesitaba.
Esta parece ser la forma más común de la cadena ISO8601 y un buen subconjunto.
Los ejemplos que dan son:
1994-11-05T08:15:30-05:00 corresponds
November 5, 1994, 8:15:30 am, US Eastern Standard Time.
1994-11-05T13:15:30Z corresponds to the same instant.
También tengo una versión rápida:
final static int SHORT_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30Z".length ();
// 01234567890123456789012
final static int LONG_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30-05:00".length ();
public static Date fromISO8601( String string ) {
if (isISO8601 ( string )) {
char [] charArray = Reflection.toCharArray ( string );//uses unsafe or string.toCharArray if unsafe is not available
int year = CharScanner.parseIntFromTo ( charArray, 0, 4 );
int month = CharScanner.parseIntFromTo ( charArray, 5, 7 );
int day = CharScanner.parseIntFromTo ( charArray, 8, 10 );
int hour = CharScanner.parseIntFromTo ( charArray, 11, 13 );
int minute = CharScanner.parseIntFromTo ( charArray, 14, 16 );
int second = CharScanner.parseIntFromTo ( charArray, 17, 19 );
TimeZone tz ;
if (charArray[19] == ''Z'') {
tz = TimeZone.getTimeZone ( "GMT" );
} else {
StringBuilder builder = new StringBuilder ( 9 );
builder.append ( "GMT" );
builder.append( charArray, 19, LONG_ISO_8601_TIME_LENGTH - 19);
String tzStr = builder.toString ();
tz = TimeZone.getTimeZone ( tzStr ) ;
}
return toDate ( tz, year, month, day, hour, minute, second );
} else {
return null;
}
}
...
public static int parseIntFromTo ( char[] digitChars, int offset, int to ) {
int num = digitChars[ offset ] - ''0'';
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
}
}
}
}
}
}
}
}
return num;
}
public static boolean isISO8601( String string ) {
boolean valid = true;
if (string.length () == SHORT_ISO_8601_TIME_LENGTH) {
valid &= (string.charAt ( 19 ) == ''Z'');
} else if (string.length () == LONG_ISO_8601_TIME_LENGTH) {
valid &= (string.charAt ( 19 ) == ''-'' || string.charAt ( 19 ) == ''+'');
valid &= (string.charAt ( 22 ) == '':'');
} else {
return false;
}
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
// "1 9 9 4 - 1 1 - 0 5 T 0 8 : 1 5 : 3 0 - 0 5 : 0 0
valid &= (string.charAt ( 4 ) == ''-'') &&
(string.charAt ( 7 ) == ''-'') &&
(string.charAt ( 10 ) == ''T'') &&
(string.charAt ( 13 ) == '':'') &&
(string.charAt ( 16 ) == '':'');
return valid;
}
No lo he evaluado, pero creo que será bastante rápido. Parece funcionar. :)
@Test
public void testIsoShortDate() {
String test = "1994-11-05T08:15:30Z";
Date date = Dates.fromISO8601 ( test );
Date date2 = Dates.fromISO8601_ ( test );
assertEquals(date2.toString (), date.toString ());
puts (date);
}
@Test
public void testIsoLongDate() {
String test = "1994-11-05T08:11:22-05:00";
Date date = Dates.fromISO8601 ( test );
Date date2 = Dates.fromISO8601_ ( test );
assertEquals(date2.toString (), date.toString ());
puts (date);
}
Hazlo asi:
public static void main(String[] args) throws ParseException {
String dateStr = "2016-10-19T14:15:36+08:00";
Date date = javax.xml.bind.DatatypeConverter.parseDateTime(dateStr).getTime();
System.out.println(date);
}
Aquí está la salida:
Mié 19 de octubre 15:15:36 CST 2016
Java tiene una docena de formas diferentes de analizar una fecha y hora, como lo demuestran las excelentes respuestas aquí. ¡Pero algo asombroso, ninguna de las clases de tiempo de Java implementa completamente ISO 8601!
Con Java 8, recomiendo:
ZonedDateTime zp = ZonedDateTime.parse(string);
Date date = Date.from(zp.toInstant());
Se manejarán 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 manejar eso, sugeriría usar primero una expresión regular para detectar 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 tengo conocimiento de ninguna clase de Java que pueda hacer frente a todos ellos.
La biblioteca Jackson-databind también tiene una clase ISO8601DateFormat que hace eso (implementación real en ISO8601Utils .
ISO8601DateFormat df = new ISO8601DateFormat();
Date d = df.parse("2010-07-28T22:25:51Z");
La forma en que ha sido SimpleDateFormat :
DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SSSZ");
String string1 = "2001-07-04T12:08:56.235-0700";
Date result1 = df1.parse(string1);
DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SSSXXX");
String string2 = "2001-07-04T12:08:56.235-07:00";
Date result2 = df2.parse(string2);
Puede encontrar más ejemplos en la sección Ejemplos en SimpleDateFormat .
La solución DatatypeConverter no funciona en todas las máquinas virtuales. Los siguientes trabajos para mí:
javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar("2011-01-01Z").toGregorianCalendar().getTime()
Descubrí que joda no funciona de manera inmediata (específicamente para el ejemplo que mencioné anteriormente con la zona horaria en una fecha, que debería ser válida)
La solución para Java 7+ es usar 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 el carácter X
y lanzará
IllegalArgumentException: Unknown pattern character ''X''
Necesitamos normalizar la fecha ISO8601 al formato legible en Java 6 con SimpleDateFormat
.
public static Date iso8601Format(String formattedDate) throws ParseException {
try {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SSSX", Locale.US);
return df.parse(formattedDate);
} catch (IllegalArgumentException ex) {
// error happen in Java 6: Unknown pattern character ''X''
if (formattedDate.endsWith("Z")) formattedDate = formattedDate.replace("Z", "+0000");
else formattedDate = formattedDate.replaceAll("([+-]//d//d):(//d//d)//s*$", "$1$2");
DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SSSZ", Locale.US);
return df1.parse(formattedDate);
}
}
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 sentencia try / catch con if).
Me enfrenté al mismo problema y lo resolví con el siguiente código.
public static Calendar getCalendarFromISO(String datestring) {
Calendar calendar = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault()) ;
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SSS''Z''", Locale.getDefault());
try {
Date date = dateformat.parse(datestring);
date.setHours(date.getHours() - 1);
calendar.setTime(date);
String test = dateformat.format(calendar.getTime());
Log.e("TEST_TIME", test);
} catch (ParseException e) {
e.printStackTrace();
}
return calendar;
}
Anteriormente estaba usando SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SSSZ", Locale.getDefault());
Pero más tarde descubrí que la causa principal de la excepción era el yyyy-MM-dd''T''HH:mm:ss.SSSZ
,
Entonces utilicé
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SSS''Z''", Locale.getDefault());
Funcionó bien para mí.
Otra forma muy sencilla de analizar las marcas de tiempo ISO8601 es usar org.apache.commons.lang.time.DateUtils
:
import static org.junit.Assert.assertEquals;
import java.text.ParseException;
import java.util.Date;
import org.apache.commons.lang.time.DateUtils;
import org.junit.Test;
public class ISO8601TimestampFormatTest {
@Test
public void parse() throws ParseException {
Date date = DateUtils.parseDate("2010-01-01T12:00:00+01:00", new String[]{ "yyyy-MM-dd''T''HH:mm:ssZZ" });
assertEquals("Fri Jan 01 12:00:00 CET 2010", date.toString());
}
}
Para Java versión 7
Puede seguir la documentación de Oracle: SimpleDateFormat
X - se utiliza para la zona horaria ISO 8601
TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ssX");
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());
System.out.println(nowAsISO);
DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ssX");
//nowAsISO = "2013-05-31T00:00:00Z";
Date finalResult = df1.parse(nowAsISO);
System.out.println(finalResult);
Para formatear una fecha como esta, lo siguiente me funcionó en una aplicación basada en Java 6. Hay una clase DateFormat
JacksonThymeleafISO8601DateFormat
en el proyecto thymeleaf que inserta el colon faltante:
Lo usé para compatibilidad de formato de fecha ECMAScript.
SimpleDateFormat para JAVA 1.7 tiene un patrón genial para el formato ISO 8601.
Aquí esta lo que hice:
Date d = new SimpleDateFormat( "yyyy-MM-dd''T''HH:mm:ss.SSSZ",
Locale.ENGLISH).format(System.currentTimeMillis());
También puedes usar la siguiente clase:
org.springframework.extensions.surf.util.ISO8601DateFormat
Date date = ISO8601DateFormat.parse("date in iso8601");
Enlace a Java Doc - Jerarquía para el paquete org.springframework.extensions.surf.maven.plugin.util
Tenía una necesidad similar: necesitaba poder analizar cualquier fecha compatible con ISO8601 sin saber el formato exacto de antemano, y quería una solución liviana que también funcionara en Android.
Cuando busqué en Google mis necesidades, me topé con esta pregunta y noté que AFAIU, ninguna respuesta se adaptaba completamente a mis necesidades. Así que desarrollé jISO8601 y lo empujé en maven central.
Solo agrega tu pom.xml
:
<dependency>
<groupId>fr.turri</groupId>
<artifactId>jISO8601</artifactId>
<version>0.2</version>
</dependency>
y entonces eres bueno para ir
import fr.turri.jiso8601.*;
...
Calendar cal = Iso8601Deserializer.toCalendar("1985-03-04");
Date date = Iso8601Deserializer.toDate("1985-03-04T12:34:56Z");
Espera que ayude.
Utilice una cadena como LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)
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 .
Creo que lo que mucha gente quiere hacer es analizar las cadenas de fecha JSON. Existe una buena posibilidad de que, si llega a esta página, desee convertir una fecha JSON de JavaScript en una fecha de Java.
Para mostrar cómo se ve una cadena de fecha JSON:
var d=new Date();
var s = JSON.stringify(d);
document.write(s);
document.write("<br />"+d);
"2013-12-14T01:55:33.412Z"
Fri Dec 13 2013 17:55:33 GMT-0800 (PST)
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 muy específico ISO 8601, mientras que ISO_8601 es mucho más grande y eso es un simple 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
De hecho, escribí un analizador JSON y un analizador PLIST, ambos de los cuales utilizan ISO-8601 pero no los mismos bits.
/*
var d=new Date();
var s = JSON.stringify(d);
document.write(s);
document.write("<br />"+d);
"2013-12-14T01:55:33.412Z"
Fri Dec 13 2013 17:55:33 GMT-0800 (PST)
*/
@Test
public void jsonJavaScriptDate() {
String test = "2013-12-14T01:55:33.412Z";
Date date = Dates.fromJsonDate ( test );
Date date2 = Dates.fromJsonDate_ ( test );
assertEquals(date2.toString (), "" + date);
puts (date);
}
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 fechas PLIST, que son un formato diferente ISO 8601).
La fecha JSON es la siguiente:
public static Date fromJsonDate_( String string ) {
try {
return new SimpleDateFormat ( "yyyy-MM-dd''T''HH:mm:ss.SSSXXX").parse ( string );
} catch ( ParseException e ) {
return Exceptions.handle (Date.class, "Not a valid JSON date", e);
}
}
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 no he encontrado uno que use milis todavía y el analizador que he visto omitir la zona horaria, OMG).
Ahora para la versión rápida (puedes encontrarla en Boon).
public static Date fromJsonDate( String string ) {
return fromJsonDate ( Reflection.toCharArray ( string ), 0, string.length () );
}
Tenga en cuenta que Reflection.toCharArray usa inseguro si está disponible, pero por defecto es string.toCharArray si no lo está.
(Puede quitarlo del ejemplo reemplazando Reflection.toCharArray (string) con string.toCharArray ()).
public static Date fromJsonDate( char[] charArray, int from, int to ) {
if (isJsonDate ( charArray, from, to )) {
int year = CharScanner.parseIntFromTo ( charArray, from + 0, from + 4 );
int month = CharScanner.parseIntFromTo ( charArray, from +5, from +7 );
int day = CharScanner.parseIntFromTo ( charArray, from +8, from +10 );
int hour = CharScanner.parseIntFromTo ( charArray, from +11, from +13 );
int minute = CharScanner.parseIntFromTo ( charArray, from +14, from +16 );
int second = CharScanner.parseIntFromTo ( charArray, from +17, from +19 );
int miliseconds = CharScanner.parseIntFromTo ( charArray, from +20, from +23 );
TimeZone tz = TimeZone.getTimeZone ( "GMT" );
return toDate ( tz, year, month, day, hour, minute, second, miliseconds );
} else {
return null;
}
}
El isJsonDate se implementa de la siguiente manera:
public static boolean isJsonDate( char[] charArray, int start, int to ) {
boolean valid = true;
final int length = to -start;
if (length != JSON_TIME_LENGTH) {
return false;
}
valid &= (charArray [ start + 19 ] == ''.'');
if (!valid) {
return false;
}
valid &= (charArray[ start +4 ] == ''-'') &&
(charArray[ start +7 ] == ''-'') &&
(charArray[ start +10 ] == ''T'') &&
(charArray[ start +13 ] == '':'') &&
(charArray[ start +16 ] == '':'');
return valid;
}
De todos modos ... supongo que muchas 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.
public static int parseIntFromTo ( char[] digitChars, int offset, int to ) {
int num = digitChars[ offset ] - ''0'';
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
if ( ++offset < to ) {
num = ( num * 10 ) + ( digitChars[ offset ] - ''0'' );
}
}
}
}
}
}
}
}
return num;
}
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.
Independientemente verificado por los dudes de Gatling Performance.
https://github.com/gatling/json-parsers-benchmark
Benchmark Mode Thr Count Sec Mean Mean error Units
BoonCharArrayBenchmark.roundRobin thrpt 16 10 1 724815,875 54339,825 ops/s
JacksonObjectBenchmark.roundRobin thrpt 16 10 1 580014,875 145097,700 ops/s
JsonSmartBytesBenchmark.roundRobin thrpt 16 10 1 575548,435 64202,618 ops/s
JsonSmartStringBenchmark.roundRobin thrpt 16 10 1 541212,220 45144,815 ops/s
GSONStringBenchmark.roundRobin thrpt 16 10 1 522947,175 65572,427 ops/s
BoonDirectBytesBenchmark.roundRobin thrpt 16 10 1 521528,912 41366,197 ops/s
JacksonASTBenchmark.roundRobin thrpt 16 10 1 512564,205 300704,545 ops/s
GSONReaderBenchmark.roundRobin thrpt 16 10 1 446322,220 41327,496 ops/s
JsonSmartStreamBenchmark.roundRobin thrpt 16 10 1 276399,298 130055,340 ops/s
JsonSmartReaderBenchmark.roundRobin thrpt 16 10 1 86789,825 17690,031 ops/s
Tiene el analizador JSON más rápido para transmisiones, lectores, bytes [], char [], CharSequence (StringBuilder, CharacterBuffer) y String.
Ver más puntos de referencia en: