在 Java Spring 引导中使用 DateTimeFormatter 时获取不受支持的字段:DayOfMonth

Getting Unsupported field: DayOfMonth while using DateTimeFormatter in Java Spring Boot

确切错误:java.time.temporal.UnsupportedTemporalTypeException:不支持的字段:DayOfMonth

下面是我创建的 HashMap,我们可以在其中看到仅存在 3 个月的数据。最终目标是 create/update 从当月开始,使用最近 12 个月的数据动态生成 MAP。

这 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);
    }
}

我们如何解决这个错误。

嗯,YearMonth 只有一个年份和一个月份字段。然后您尝试使用 ISO_LOCAL_DATE_TIME 格式化程序对其进行格式化,它期望 Temporal(在您的情况下为 YearMonth)支持日期字段。

那显然不行。

您可以使用 YearMonthatDay 方法,该方法将 YearMonth 转换为具有指定日期的 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 个值,否则我们将有一个无限流。
  • 第一个 mapYearMonth 转换为带有月份第一天的 LocalDate。然后使用模式 uuuu-MM-dd.
  • 对其进行格式化
  • 第二个 map 创建一个 Map.Entry ,其中流元素作为键,值是来自 expectedValues 映射的值,或者 0L 如果是键不存在。当然,这两个 map 调用可以合并。
  • 然后我们收集流中当前包含的这些Map.Entry<String, Long>个元素,到一个Map.

Demo