Solución:
Desafortunadamente, los formatos de zona horaria disponibles para SimpleDateFormat (Java 6 y versiones anteriores) no son compatibles con ISO 8601. SimpleDateFormat comprende cadenas de zonas horarias como “GMT + 01: 00” o “+0100”, este último de acuerdo con 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 expresiones regulares es ciertamente una posibilidad, pero las reglas de reemplazo no son tan simples como en su pregunta:
- Algunas zonas horarias no tienen horas completas fuera de UTC, por lo que la cadena no necesariamente termina en “: 00”.
- ISO8601 permite que solo se incluya el número de horas en la zona horaria, por lo que “+01” equivale a “+01: 00”.
- ISO8601 permite el uso de “Z” para indicar UTC en lugar de “+00: 00”.
La solución más sencilla es posiblemente utilizar el convertidor de tipos 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")
te dará un Calendar
objeto y puede simplemente usar getTime () en él, si necesita un Date
objeto.
Probablemente también podrías usar Joda-Time, pero no sé por qué deberías molestarte con eso.
La forma en que está bendecido por la documentación de Java 7:
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 de en SimpleDateFormat javadoc.
UPD 13/02/2020: Hay una forma completamente nueva de hacer esto en Java 8
De acuerdo, esta pregunta ya está respondida, pero dejaré mi respuesta de todos modos. Podría ayudar a alguien.
He estado buscando un solución para Android (API 7).
- Joda estaba fuera de discusión: es enorme y sufre de una inicialización lenta. También parecía una exageración importante para ese propósito en particular.
- Respuestas que involucran
javax.xml
no funcionará en la API de Android 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 esta 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: Siempre instalo un nuevo SimpleDateFormat como medio 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).