java - illegal - SimpleDateFormat no está analizando los milisegundos correctamente
java lang illegalargumentexception illegal pattern character t (4)
Fondo:
En mi tabla de base de datos, tengo dos marcas de tiempo
timeStamp1 = 2011-08-23 14:57:26.662
timeStamp2 = 2011-08-23 14:57:26.9
Cuando hago un "ORDER BY TIMESTAMP ASC", timeStamp2 se considera como la marca de tiempo mayor (que es correcta).
Requisito: Necesito obtener la diferencia de estas marcas de tiempo (timeStamp2 - timeStamp1)
Mi implementación:
public static String timeDifference(String now, String prev) {
try {
final Date currentParsed = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(now);
final Date previousParsed = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(prev);
long difference = currentParsed.getTime() - previousParsed.getTime();
return "" + difference;
} catch (ParseException e) {
return "Unknown";
}
}
La respuesta debería haber sido 238ms, pero el valor que se devuelve es -653ms. No estoy seguro de lo que estoy haciendo mal. ¿Alguna sugerencia?
El formato que está analizando y los usos de formato no coinciden. Esperas un campo de tres dígitos y solo estás proporcionando un dígito. Toma 9
y asume que te refieres a 009
cuando lo que quieres es 900
. Los formatos de fecha son complicados y cuando prueba las fechas en un formato diferente, puede analizarlos de manera diferente a usted.
La documentación dice que S
significa el número de milisegundos y el número en ese campo es 9, por lo que se está comportando correctamente.
EDIT: este ejemplo puede ayudar
final SimpleDateFormat ss_SSS = new SimpleDateFormat("ss.SSS");
ss_SSS.setTimeZone(TimeZone.getTimeZone("GMT"));
for (String text : "0.9, 0.456, 0.123456".split(", ")) {
System.out.println(text + " parsed as /"ss.SSS/" is "
+ ss_SSS.parse(text).getTime() + " millis");
}
huellas dactilares
0.9 parsed as "ss.SSS" is 9 millis
0.456 parsed as "ss.SSS" is 456 millis
0.123456 parsed as "ss.SSS" is 123456 millis
No estoy completamente seguro, pero el JavaDoc dice esto:
Para el análisis, el número de letras de patrón se ignora a menos que sea necesario para separar dos campos adyacentes.
Esto indica que los milisegundos de 2011-08-23 14:57:26.9
se analizarán como 9
lugar de 900
. Agregar los ceros al final podría funcionar: 2011-08-23 14:57:26.900
.
Tuve el mismo problema con la hora demasiado precisa de mis archivos de registro con milisegundos de 6 dígitos. Tiempo de análisis dio hasta 16 minutos de diferencia! WTF?
16-JAN-12 04.00.00.999999 PM GMT --> 16 Jan 2012 04:16:39 GMT
Cambiar el número de dígitos redujo la diferencia errónea y gracias a este hilo pude identificar el problema:
16-JAN-12 04.00.00.99999 PM GMT --> 16 Jan 2012 04:01:39 GMT
16-JAN-12 04.00.00.9999 PM GMT --> 16 Jan 2012 04:00:09 GMT
16-JAN-12 04.00.00.999 PM GMT --> 16 Jan 2012 04:00:00 GMT
Como SimpleDateFormat
maneja internamente solo 3 dígitos, SimpleDateFormat
lo innecesario con una expresión regular pequeña (ignorando los errores de redondeo, trabajando para 1 hasta n dígitos):
str = str.replaceAll("(//.[0-9]{3})[0-9]*( [AP]M)", "$1$2");
Gracias a @Peter Lawrey por su respuesta, me impidió volverme loco :-)
Yo sugeriría usar Joda-Time . Maneja estas situaciones adecuadamente. En el siguiente ejemplo, los milisegundos se analizan correctamente como 200 ms.
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class ParseMillis {
public static void main(String[] args) {
String s = "00:00:01.2";
DateTimeFormatter format = DateTimeFormat.forPattern("HH:mm:ss.S");
DateTime dateTime = format.parseDateTime(s);
System.out.println(dateTime.getMillisOfSecond());
}
}