Каков стандартный способ анализа различных дат, переданных в виде параметров запроса в API REST? - PullRequest
0 голосов
/ 28 сентября 2018

Я работаю над REST API, который поддерживает Date как параметр запроса.Так как это параметр запроса, это будет строка.Теперь Дата может быть отправлена ​​в следующих форматах в QueryParams:

yyyy-mm-dd[(T| )HH:MM:SS[.fff]][(+|-)NNNN] 

Это означает, что следующие действительные даты:

2017-05-05 00:00:00.000+0000
2017-05-05 00:00:00.000
2017-05-05T00:00:00
2017-05-05+0000
2017-05-05

Теперь, чтобы проанализировать все эти разные даты и времени, яиспользуя Java8 datetime API.Код приведен ниже:

DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive()
    .append(DateTimeFormatter.ofPattern("yyyy-MM-dd[[ ][['T'][ ]HH:mm:ss[.SSS]][Z]"))
    .toFormatter(); 
LocalDateTime localDateTime = null;
LocalDate localDate = null;
ZoneId zoneId = ZoneId.of(ZoneOffset.UTC.getId());
Date date = null;

try {
    localDateTime = LocalDateTime.parse(datetime, formatter);
    date = Date.from(localDateTime.atZone(zoneId).toInstant());
} catch (Exception exception) {
    System.out.println("Inside Excpetion");
    localDate = LocalDate.parse(datetime, formatter);
    date = Date.from(localDate.atStartOfDay(zoneId).toInstant());
}

Как видно из кода, который я использую DateTimeFormatter и добавляющего шаблон.Теперь я сначала пытаюсь разобрать дату как LocalDateTime в try-block, и если она выдает исключение для случаев, таких как 2017-05-05, так как время не прошло, я использую LocalDate в catch block.

Приведенный выше подход дает мне решение, которое я ищу, но мои вопросы таковы: является ли это стандартным способом работы с датой, отправленной в виде строки, и соответствует ли мой подход этим стандартам?

Кроме того, если это возможно, каким-то другим способом я могу проанализировать различные виды дат (показанные как действительные даты выше), за исключением некоторых других простых решений, таких как использование списка Array и размещение всех возможных форматов, а затем использованиецикл for пытается разобрать дату?

Ответы [ 2 ]

0 голосов
/ 29 сентября 2018
    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            // time is optional
            .optionalStart()
            .parseCaseInsensitive()
            .appendPattern("[ ]['T']")
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .optionalEnd()
            // offset is optional
            .appendPattern("[xx]")
            .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
            .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
            .toFormatter();
    for (String queryParam : new String[] {
            "2017-05-05 00:00:00.000+0000",
            "2017-05-05 00:00:00.000",
            "2017-05-05T00:00:00",
            "2017-05-05+0000",
            "2017-05-05",
            "2017-05-05T11:20:30.643+0000",
            "2017-05-05 16:25:09.897+0000",
            "2017-05-05 22:13:55.996",
            "2017-05-05t02:24:01"
    }) {
        Instant inst = OffsetDateTime.parse(queryParam, formatter).toInstant();
        System.out.println(inst);
    }

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

2017-05-05T00:00:00Z
2017-05-05T00:00:00Z
2017-05-05T00:00:00Z
2017-05-05T00:00:00Z
2017-05-05T00:00:00Z
2017-05-05T11:20:30.643Z
2017-05-05T16:25:09.897Z
2017-05-05T22:13:55.996Z
2017-05-05T02:24:01Z

Используемые мной приемы включают в себя:

  • Дополнительные компоненты могут быть включены в optionalStart / optionalEnd или [] по шаблону.Я использую оба, каждый из которых мне легче читать, и вы можете предпочесть их по-разному.
  • Уже есть предопределенные форматеры для даты и времени дня, поэтому я использую их повторно.В частности, я пользуюсь тем фактом, что DateTimeFormatter.ISO_LOCAL_TIME уже обрабатывает необязательные секунды и доли секунды.
  • Для синтаксического анализа в OffsetDateTime нам нужно предоставить значения по умолчанию для частей, которые могут отсутствовать впараметр запроса.parseDefaulting делает это.

В вашем коде вы конвертируете в Date.Класс java.util.Date давно устарел и имеет ряд проблем с дизайном, поэтому избегайте его, если можете.Instant все будет хорошо.Если вам нужно Date для устаревшего API, который вы не можете изменить или не хотите изменять сейчас, выполните преобразование таким же образом, как и в вопросе.

РЕДАКТИРОВАТЬ: теперь по умолчанию HOUR_OF_DAY, а не MILLI_OF_DAY.Последний вызвал конфликт, когда отсутствовал только миллис, но, похоже, форматировщик был доволен только днем ​​по умолчанию, когда время отсутствовало.

0 голосов
/ 28 сентября 2018

Я обычно использую DateUtils.parseDate , который принадлежит commons-lang .

Этот метод выглядит следующим образом:

public static Date parseDate(String str,
                         String... parsePatterns)
                  throws ParseException

Вот описание:

Разбирает строку, представляющую дату, пробуя различные парсеры.

Разбор будет пробовать каждый шаблон разбора по очереди.Разбор считается успешным, только если он анализирует всю входную строку.Если шаблоны разбора не совпадают, генерируется исключение ParseException.

Анализатор будет снисходительным к анализируемой дате.

...