Мягкий анализ даты Java 8

Я хотел бы разобрать "2015-10-01" с помощью LocalDateTime. Что я должен сделать, это

LocalDate localDate = LocalDate.parse('2015-10-01');
LocalDateTime localDateTime = localDateTime.of(localDate, LocalTime.MIN);

Но я хотел бы разобрать его за один проход, например

// throws DateTimeParseException
LocalDateTime date = LocalDateTime.parse('2015-10-01', DateTimeFormatter.ISO_LOCAL_DATE);

Также небольшая разница в строке также вызывает исключение.

// throws DateTimeParseException
LocalDate localDate = LocalDate.parse("2015-9-5", DateTimeFormatter.ISO_LOCAL_DATE);

Могу ли я снисходительно анализировать строки даты с помощью API-интерфейсов Java 8 Date?


person Sanghyun Lee    schedule 06.10.2015    source источник


Ответы (4)


Если вы хотите проанализировать строку даты как объекты "2015-10-01" и "2015-9-5" в LocalDateTime, вы можете создать свой собственный DateTimeFormatter, используя DateTimeFormatterBuilder:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                                        .appendPattern("yyyy")
                                        .appendLiteral('-')
                                        .appendValue(MONTH_OF_YEAR)
                                        .appendLiteral('-')
                                        .appendValue(DAY_OF_MONTH)
                                        .parseDefaulting(HOUR_OF_DAY, HOUR_OF_DAY.range().getMinimum())
                                        .parseDefaulting(MINUTE_OF_HOUR, MINUTE_OF_HOUR.range().getMinimum())
                                        .parseDefaulting(SECOND_OF_MINUTE, SECOND_OF_MINUTE.range().getMinimum())
                                        .parseDefaulting(NANO_OF_SECOND, NANO_OF_SECOND.range().getMinimum())
                                        .toFormatter();
System.out.println(LocalDateTime.parse("2015-9-5", formatter));
System.out.println(LocalDateTime.parse("2015-10-01", formatter));

Переменная длина каждого поля обрабатывается вызовом appendValue(field). Цитирую Javadoc:

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

Это означает, что он сможет анализировать месяц и дни, отформатированные с 1 или 2 цифрами.

Чтобы построить LocalDateTime, нам также нужно предоставить LocalTime этому строителю. Это делается с помощью parseDefaulting(field, value) для каждого поля LocalTime. Этот метод принимает поле и значение по умолчанию для этого поля, если оно отсутствует в строке для анализа. Поскольку в нашем случае в String не будет информации о времени, будут выбраны значения по умолчанию, т.е. минимальное значение диапазона допустимых значений для этого поля (получается вызовом getMinimum в ValueRange этого поля; возможно, мы могли бы также жестко закодировать здесь 0 ).


В случае, если строка для анализа может содержать информацию о времени, мы можем использовать необязательные разделы DateTimeFormatter, например:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                                        .appendPattern("yyyy")
                                        .appendLiteral('-')
                                        .appendValue(MONTH_OF_YEAR)
                                        .appendLiteral('-')
                                        .appendValue(DAY_OF_MONTH)
                                        .appendPattern("[ HH:mm]") // optional sections are surrounded by []
                                        .parseDefaulting(HOUR_OF_DAY, HOUR_OF_DAY.range().getMinimum())
                                        .parseDefaulting(MINUTE_OF_HOUR, MINUTE_OF_HOUR.range().getMinimum())
                                        .parseDefaulting(SECOND_OF_MINUTE, SECOND_OF_MINUTE.range().getMinimum())
                                        .parseDefaulting(NANO_OF_SECOND, NANO_OF_SECOND.range().getMinimum())
                                        .toFormatter();
System.out.println(LocalDateTime.parse("2015-9-5", formatter));
System.out.println(LocalDateTime.parse("2015-10-01", formatter));
System.out.println(LocalDateTime.parse("2015-1-1 10:10", formatter));
person Tunaki    schedule 06.10.2015

Простое решение для вашего конкретного случая использования — определить собственный формат. В этом примере, несмотря на то, что я указал один M для месяца в своем шаблоне и один d для дня, он по-прежнему анализирует оба примера одинаково.

@Test
public void parsing_singleDigitDates_andDoubleDigitDates_areEqual()
{
    DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-M-d");

    LocalDate dt1 = LocalDate.parse("2015-09-05", fmt);
    LocalDate dt2 = LocalDate.parse("2015-9-5", fmt);

    Assert.assertEquals(dt1, dt2);
}

Я решил написать этот ответ после того, как увидел суп с кодом, который DateTimeFormatterBuilder требует от вас написать, чтобы решить ту же проблему.

person Brad    schedule 28.09.2018

Дата и время анализа

Чтобы создать объект LocalDateTime из строки, вы можете использовать статический метод LocalDateTime.parse(). Он принимает строку и DateTimeFormatter в качестве параметра. DateTimeFormatter используется для указания шаблона даты/времени.

String str = "1986-04-08 12:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(str, formatter);

Форматирование даты и времени

Чтобы создать форматированную строку из объекта LocalDateTime, вы можете использовать метод format().

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.of(1986, Month.APRIL, 8, 12, 30);
String formattedDateTime = dateTime.format(formatter); // "1986-04-08 12:30"

Обратите внимание, что некоторые часто используемые форматы даты/времени предопределены как константы в DateTimeFormatter. Например: использование DateTimeFormatter.ISO_DATE_TIME для форматирования экземпляра LocalDateTime, указанного выше, приведет к строке «1986-04-08T12:30:00».

Методы parse() и format() доступны для всех объектов, связанных с датой/временем (например, LocalDate или ZonedDateTime).

person Ankush soni    schedule 06.10.2015
comment
Извините, пожалуйста, внимательно прочитайте вопрос. Я не спрашиваю об использовании. - person Sanghyun Lee; 06.10.2015

Можешь попробовать

    private static final DateTimeFormatter formatter =
                DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").withResolverStyle(ResolverStyle.LENIENT);
person super1ha1    schedule 01.03.2018
comment
Спасибо за ответ, но это не то, что я хотел. Для этого я должен предоставить текст в правильном формате. Это снисходительно по-другому. - person Sanghyun Lee; 01.03.2018