Получение неподдерживаемого поля: День месяца при использовании DateTimeFormatter в Java Spring Boot

#java #datetime #datetime-format #java-time

Вопрос:

Точная ошибка: java.time.temporal.Исключение UnsupportedTemporalTypeException: Неподдерживаемое поле: День месяца

Ниже приведена созданная мной хэш-карта, на которой мы видим, что данные представлены только за 3 месяца. Конечная цель состоит в том, чтобы динамически создавать/обновлять КАРТУ с использованием последних 12 мотыльков данных, начиная с текущего месяца.

Любой месяц, отличный от этих 3 месяцев, будет иметь значение 0L.

 Map<String, Long> expectedValues = new HashMap<>();
expectedValues.put("2021-06-01", 10L);
expectedValues.put("2021-07-01", 20L);
expectedValues.put("2021-08-01", 30L);
 

Я написал эту логику, чтобы проверить и заполнить 0L за несуществующие месяцы. Однако возникает ошибка при использовании DateTimeFormatter

 YearMonth thisMonth = YearMonth.now();
for (int i = 0; i < 12; i  ) {
    // DateTimeFormatter monthYearFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    DateTimeFormatter monthYearFormatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
    String prevYearMonthStr = thisMonth.minusMonths(i).format(monthYearFormatter);
    if (!expectedValues.containsKey(prevYearMonthStr)) {
        expectedValues.put(prevYearMonthStr, 0L);
    }
}
 

Как мы можем исправить эту ошибку.

Комментарии:

1. У A YearMonth нет дня, поэтому вы не можете использовать форматер, который ему нужен.

2. Вы уверены, что хотите, чтобы ключ карты expectedValues был a String ? Конечно, это зависит от вашего точного варианта использования, но в целом я бы использовал a LocalDate вместо этого.

3. @MC Император Да, вариант использования требует, чтобы это была строка.

4. Вы используете a String , который представляет полную дату ( LocalDate ) с указанием года, месяца года и дня месяца, но у a YearMonth нет дня месяца. Не можете ли вы вместо этого использовать String s как "2021-06" и анализировать их с помощью a DateTimeFormatter.ofPattern("uuuu-MM") ?

5. Нет, мне нужно в формате «2021-08-01». Есть ли какой-либо пакет, кроме годового, который может служить этой цели ?

Ответ №1:

Ну, YearMonth есть только поле на год и месяц. Затем вы пытаетесь отформатировать его с помощью ISO_LOCAL_DATE_TIME форматера, который ожидает Temporal , что (в вашем случае YearMonth ) будет поддерживать поле дня месяца.

Это, очевидно, не сработает.

Вы можете использовать YearMonth atDay метод s, который преобразует значение YearMonth в a LocalDate с указанным днем месяца. Затем это LocalDate можно отформатировать с помощью предопределенного ISO_LOCAL_DATE форматера, который равен форматеру со строкой шаблона uuuu-MM-dd .

 YearMonth thisMonth = YearMonth.now();
DateTimeFormatter format = DateTimeFormatter.ISO_LOCAL_DATE;
for (int i = 0; i < 12; i  ) {
    String prev = thisMonth.minusMonths(i).atDay(1).format(format);
    if (!expectedValues.containsKey(prev)) {
        expectedValues.put(prev, 0L);
    }
}
 

Demo

Или с использованием функций Java 8:

 static Map<String, Long> transform(Map<String, Long> expectedValues) {
    DateTimeFormatter format = DateTimeFormatter.ISO_LOCAL_DATE;
    return Stream.iterate(YearMonth.now(), ym -> ym.minusMonths(1))
        .limit(12)
        .map(ym -> ym.atDay(1).format(format))
        .map(str -> Map.entry(str, expectedValues.getOrDefault(str, 0L)))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
 

Вот что здесь происходит:

  • Stream::iterate принимает начальное значение, которое является текущим месяцем, а затем повторяет каждый месяц в прошлом.
  • limit убедитесь, что у нас есть 12 значений, иначе у нас был бы бесконечный поток.
  • Первый map преобразует YearMonth в а LocalDate с первого дня месяца. Затем он форматирует его, используя шаблон uuuu-MM-dd .
  • Второй map создает Map.Entry элемент с потоком в качестве ключа и в качестве значения либо значение из expectedValues карты, либо 0L , если ключ не существует. Конечно, эти два map вызова можно было бы объединить.
  • Затем мы собираем эти Map.Entry<String, Long> элементы, содержащиеся в настоящее время в потоке, в a Map .

Demo

Комментарии:

1. Я попробовал первое решение, оно выдает эту ошибку сейчас — Неподдерживаемое поле: HourOfDay.

2. @sandeep Вы используете ISO_LOCAL_DATE_TIME , в то время как в моем примере я использую ISO_LOCAL_DATE .

3. Спасибо, что поправили меня. Теперь решение работает для меня.