Безопасный разбор SimpleDateFormat - PullRequest
2 голосов
/ 09 апреля 2019

У меня есть небольшой блок кода, который анализирует время генерации ответа из самого ответа и превращает его в дату для будущих целей. Это выглядит так:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
Date responseTime = sdf.parse(RStime);

И это почти работает как шарм. Чтобы быть точным, он работает в 99,9% случаев, за исключением одного случая: когда миллисекундная часть равна 000, то сервер вообще не добавляет .000 миллисекунд, поэтому у нас есть проблема.

Теперь, согласно SimpleDateFormat docs , если при синтаксическом анализе происходит сбой, функция возвращает ноль. Тем не менее, я, вероятно, неверно истолковал его, поскольку он просто создает исключение.

Я очень новичок в Java и в механизмах try-catch, поэтому кто-нибудь может предложить элегантное и полезное решение для обработки таких случаев?

Спасибо!

Ответы [ 4 ]

1 голос
/ 09 апреля 2019

java.time

String rsTime = "2018-04-09T10:47:16.999-02:00";
OffsetDateTime responseTime = OffsetDateTime.parse(rsTime);
System.out.println("Parsed date and time: " + responseTime);

Выходные данные этого фрагмента:

Дата и время анализа: 2018-04-09T10: 47: 16.999-02: 00

Работает так же хорошо для версии с пропущенными тысячами миллисекунд:

String rsTime = "2018-04-09T10:47:16-02:00";

Дата и время анализа: 2018-04-09T10: 47: 16-02:00

Используемые вами классы SimpleDateFormat и Date плохо разработаны и давно устарели (первые особенно печально известны).Так что не только в этом конкретном случае я рекомендую использовать вместо этого java.time, современный Java-интерфейс даты и времени.Однако строки с вашего сервера имеют формат ISO 8601, и OffsetDateTime и другие классы java.time анализируют этот формат как формат по умолчанию, то есть без какого-либо явного средства форматирования, что уже значительно облегчает задачу.Кроме того, в стандарте дробные секунды являются необязательными, поэтому оба варианта строки анализируются без каких-либо проблем.OffsetDateTime также печатает ISO 8601 обратно из его метода toString, поэтому в обоих случаях печатается строка, идентичная проанализированной.

Только в том случае, если вам необходим старомодный DateОбъект для устаревшего API, который вы не можете изменить прямо сейчас, конвертируйте так:

Instant responseInstant = responseTime.toInstant();
Date oldfashionedDateObject = Date.from(responseInstant);
System.out.println("Converted to old-fashioned Date: " + oldfashionedDateObject);

Вывод на моем компьютере в часовом поясе Европы / Копенгагена:

Преобразован в старыйFashioned Дата: Пн Апр 09 14:47:16 CEST 2018

Ссылка: Обучающая программа Oracle: Дата Время , объясняющая, как использовать java.time.

0 голосов
/ 09 апреля 2019

Это действительно исключительная ситуация?Если это не так, вы, вероятно, не должны использовать исключения в этом случае.На мой взгляд, это нормально, что время может закончиться с .000ms.В этом случае вы можете проверить, содержит ли строка . (точка) и, если нет, добавить .000 до конца.

if(!RStime.contains(".")){
    RStime+=".000";
}

Редактировать: Я забыл о часовом поясе в строке времени.Вам, вероятно, нужно что-то более сложное для этого.Что-то вроде этого должно сделать это:

if(!RStime.contains(".")){
    String firstPart = RStime.substring(0, 21);
    String secondPart = RStime.substring(21);
    RStime = firstPart + ".000" + secondPart;
}
0 голосов
/ 09 апреля 2019

Вы можете проверить точку, а затем использовать первый или второй формат:

String timeString = "2018-04-09T10:47:16.999-02:00";
//String timeString = "2018-04-09T10:47:16-02:00";
String format = timeString.contains(".") ? "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" : "yyyy-MM-dd'T'HH:mm:ssXXX";
Date responseTime = new SimpleDateFormat(format).parse(timeString);
System.out.println("responseTime: " + responseTime);

Если вы закомментируете первую строку, а затем закомментируете вторую и снова запустите ее, она выведет:

responseTime: Mon Apr 09 14:47:16 CEST 2018

Кстати:

  • Java 7 (очевидно, используемая вами версия) возвращает java.text.ParseException: Unparseable date: "2018-04-09T10:47:16-02:00"

  • Дополнительные функции поддерживаются начиная с Java 8.

0 голосов
/ 09 апреля 2019

В соответствии с SimpleDateFormat doc , о котором вы упомянули метод parse:

public Date parse(String text, ParsePosition pos)

Броски:

NullPointerException - если text или pos имеет значение null.

Таким образом, один вариант - перехватить это исключение и сделать то, что вам нужно внутри перехвата, например:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
try {
  Date responseTime = sdf.parse(RStime, position);
} catch (NullPointerException e) {
  e.printStackTrace();
  //... Do extra stuff if needed
}

Или унаследованный метод от DateFormat :

public Date parse(String source)

Броски:

ParseException - ifначало указанной строки не может быть проанализировано.

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
try {
  Date responseTime = sdf.parse(RStime);
} catch (ParseException e) {
  e.printStackTrace();
  //... Do extra stuff if needed
}
...