SimpleDateFormat не обрабатывает миллисекунды правильно
Фон:
В моей таблице базы данных есть две метки времени
timeStamp1 = 2011-08-23 14:57:26.662
timeStamp2 = 2011-08-23 14:57:26.9
Когда я выполняю "ORDER BY TIMESTAMP ASC", timeStamp2 считается большей меткой времени (что является правильным).
Требование: Мне нужно получить разницу этих временных меток (timeStamp2 - timeStamp1)
Моя реализация:
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";
}
}
Ответ должен был быть 238 мс, но возвращаемое значение - -653мс.
Я не уверен, что я делаю неправильно. Любые предложения?
Ответы
Ответ 1
Я не совсем уверен, но JavaDoc утверждает это:
Для синтаксического анализа количество букв шаблонов игнорируется, если не требуется разделять два смежных поля.
Это означает, что миллисекунды из 2011-08-23 14:57:26.9
будут обрабатываться как 9
вместо 900
. Добавление конечных нулей может работать: 2011-08-23 14:57:26.900
.
Ответ 2
Формат, который вы обрабатываете, и использование формата не соответствует. Вы ожидаете трехзначное поле и получаете только одну цифру. Он принимает 9
и предполагает, что вы имеете в виду 009
, когда вы хотите 900
. Форматы даты сложны, и когда вы доказываете даты в другом формате, они могут различать их по-разному.
В документации указано, что S
означает количество миллисекунд, а число в этом поле равно 9, поэтому оно ведет себя правильно.
EDIT: этот пример может помочь
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");
}
печатает
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
Ответ 3
У меня была такая же проблема со слишком точным временем из моих лог файлов с 6-значным миллисекундом. Parsing Time дал разницу в 16 минут! WTF?
16-JAN-12 04.00.00.999999 PM GMT --> 16 Jan 2012 04:16:39 GMT
Изменение количества цифр уменьшило ошибочную разницу и благодаря этой теме я мог бы идентифицировать проблему:
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
Поскольку SimpleDateFormat
внутренне обрабатывает только 3 цифры, я удалял ненужное с помощью небольшого регулярного выражения (игнорируя ошибки округления, работая от 1 до n цифр):
str = str.replaceAll("(\\.[0-9]{3})[0-9]*( [AP]M)", "$1$2");
Спасибо @Peter Lawrey за ваш ответ, не позволил мне сойти с ума: -)
Ответ 4
Я бы предложил использовать Joda-Time. Он правильно справляется с этими ситуациями. В следующем примере миллисекунды корректно обрабатываются как 200 мс.
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());
}
}