SimpleDateFormat неправильно анализирует миллисекунды - PullRequest
26 голосов
/ 23 августа 2011

Справочная информация:

В моей таблице базы данных у меня есть две метки времени

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 мс. Я не уверен, что я делаю неправильно. Есть предложения?

Ответы [ 4 ]

17 голосов
/ 23 августа 2011

Формат, который вы анализируете, и используемый формат не совпадает.Вы ожидаете трехзначное поле и предоставляете только одну цифру.Это займет 9 и предполагает, что вы имеете в виду 009, когда вы хотите 900.Форматы даты являются сложными, и когда вы проверяете даты в другом формате, они могут анализировать их по-разному для вас.

В документации указано, что S означает количество миллисекунд, а число в этом поле равно 9, поэтомуон ведет себя правильно.


РЕДАКТИРОВАТЬ: Этот пример может помочь

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
12 голосов
/ 23 августа 2011

Я не совсем уверен, но JavaDoc утверждает следующее:

При синтаксическом анализе количество букв шаблона игнорируется, если только это не необходимо для разделения двух соседних полей.

Это указывает, что миллисекунды с 2011-08-23 14:57:26.9 будут анализироваться как 9 вместо 900.Добавление конечных нулей может работать: 2011-08-23 14:57:26.900.

3 голосов
/ 27 ноября 2013

Я бы предложил использовать 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());
  }
}
3 голосов
/ 17 января 2012

У меня была та же проблема со слишком точным временем из моих лог-файлов с 6-значными миллисекундами.Время разбора дало разницу до 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 за ваш ответ, помешавший мне идтибезумный: -)

...