#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
был aString
? Конечно, это зависит от вашего точного варианта использования, но в целом я бы использовал aLocalDate
вместо этого.3. @MC Император Да, вариант использования требует, чтобы это была строка.
4. Вы используете a
String
, который представляет полную дату (LocalDate
) с указанием года, месяца года и дня месяца, но у aYearMonth
нет дня месяца. Не можете ли вы вместо этого использоватьString
s как"2021-06"
и анализировать их с помощью aDateTimeFormatter.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);
}
}
Или с использованием функций 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>
элементы, содержащиеся в настоящее время в потоке, в aMap
.
Комментарии:
1. Я попробовал первое решение, оно выдает эту ошибку сейчас — Неподдерживаемое поле: HourOfDay.
2. @sandeep Вы используете
ISO_LOCAL_DATE_TIME
, в то время как в моем примере я используюISO_LOCAL_DATE
.3. Спасибо, что поправили меня. Теперь решение работает для меня.