Java DateTimeFormatter解析挪威语短月份日期失败问题
问题原因分析
核心原因
Java 中挪威语 Locale(如 nb-NO)对应的月份短格式(MMM)默认包含句点后缀。以四月为例,TextStyle.SHORT 对应的缩写是 apr.,而非你输入中的 apr(无句点)。
当你使用模式 d. MMM yyyy HH:mm 解析 8. apr 2024 15:32 时,解析器会在索引3的位置(apr 起始处)期望匹配带句点的月份缩写,但输入中没有句点,直接导致匹配失败,抛出 DateTimeParseException。
而尝试用 d. MMM. yyyy HH:mm 解析 8. apr. 2024 15:32 时,模式中的 MMM. 会要求匹配 apr..(因为 MMM 本身对应 apr.,额外的句点会叠加),但输入仅为 apr.,同样无法匹配,引发异常。
验证方式
你可以通过以下代码打印挪威语 Locale 下的月份短缩写,确认默认格式:
import java.time.Month; import java.time.format.TextStyle; import java.util.Locale; public class TestMonthAbbr { public static void main(String[] args) { Locale norwegian = Locale.forLanguageTag("nb"); for (Month month : Month.values()) { System.out.println(month.getDisplayName(TextStyle.SHORT, norwegian)); } } }
输出的四月缩写会是 apr.,带句点后缀。
解决思路
- 调整输入字符串:如果可控,将输入中的月份缩写改为带句点的格式(如
apr.),直接使用d. MMM yyyy HH:mm模式即可解析。 - 自定义月份解析规则:通过
DateTimeFormatterBuilder手动映射无句点的月份缩写,示例如下:
import java.time.LocalDateTime; import java.time.Month; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.ChronoField; import java.util.HashMap; import java.util.Locale; import java.util.Map; public class DateParser { public static LocalDateTime parseDatoLocalDateTime2(String datoString, String language) { // 针对挪威语无句点的月份缩写自定义映射 Map<String, Month> monthMap = new HashMap<>(); monthMap.put("jan", Month.JANUARY); monthMap.put("feb", Month.FEBRUARY); monthMap.put("mar", Month.MARCH); monthMap.put("apr", Month.APRIL); monthMap.put("mai", Month.MAY); monthMap.put("jun", Month.JUNE); monthMap.put("jul", Month.JULY); monthMap.put("aug", Month.AUGUST); monthMap.put("sep", Month.SEPTEMBER); monthMap.put("okt", Month.OCTOBER); monthMap.put("nov", Month.NOVEMBER); monthMap.put("des", Month.DECEMBER); DateTimeFormatter formatter = new DateTimeFormatterBuilder() .parseCaseInsensitive() .appendPattern("d. ") .appendText(ChronoField.MONTH_OF_YEAR, monthMap) // 使用自定义映射 .appendPattern(" yyyy HH:mm") .toFormatter(Locale.forLanguageTag(language)); return LocalDateTime.parse(datoString, formatter); } }
- 使用宽松解析(谨慎使用):添加
parseLenient()配置,但这种方式可能会引入意外的匹配逻辑,仅在确保输入格式稳定的场景下使用:
DateTimeFormatter formatter = new DateTimeFormatterBuilder() .parseCaseInsensitive() .parseLenient() .appendPattern(pattern) .toFormatter(Locale.forLanguageTag(language));
内容的提问来源于stack exchange,提问作者kakemonsteret
相关产品推荐
相关产品推荐

