Java使用DateTimeFormatter解析西班牙语日期字符串转LocalDate报错
问题根因
异常提示字符串28-dic-2017在索引3位置解析失败,这个位置正好是月份缩写dic的起始点,匹配失败的核心原因有两个:
DateTimeFormatter默认启用大小写敏感的严格解析规则,OpenJDK内置es-ES语言环境的标准月份缩写为首字母大写格式(十二月对应的标准缩写为Dic),和CSV中全小写的dic格式不匹配- 部分老旧JDK版本(如JDK 8早期版本)内置的CLDR本地化数据收录不全,未覆盖es-ES场景下这类全小写、无句点的月份缩写形式,哪怕调整大小写规则也可能出现解析不通过的问题。
修复方案
方案1:调整解析规则适配小写月份缩写
通过DateTimeFormatterBuilder显式开启不区分大小写的解析模式,放宽匹配要求,适配CSV中的全小写格式:
public static LocalDate parseDate(String fecha) { Locale loc = new Locale("es", "ES"); DateTimeFormatter formatter = new DateTimeFormatterBuilder() // 开启不区分大小写解析 .parseCaseInsensitive() .appendPattern("dd-MMM-yyyy") .toFormatter(loc); return LocalDate.parse(fecha, formatter); }
方案2:自定义月份缩写映射(解决跨JDK版本兼容问题)
如果调整大小写规则后仍解析失败,说明当前JDK版本的内置本地化数据不匹配,可直接显式注册西班牙语全小写月份缩写字典,完全不依赖内置CLDR数据,从根源上避免版本差异问题:
public static LocalDate parseDate(String fecha) { // 定义西班牙语12个月份的全小写缩写映射 Map<Long, String> spanishMonthAbbrev = Map.of( 1L, "ene", 2L, "feb", 3L, "mar", 4L, "abr", 5L, "may", 6L, "jun", 7L, "jul", 8L, "ago", 9L, "sep", 10L, "oct", 11L, "nov", 12L, "dic" ); DateTimeFormatter formatter = new DateTimeFormatterBuilder() .parseCaseInsensitive() .appendValue(ChronoField.DAY_OF_MONTH, 2) .appendLiteral('-') // 用自定义字典替换默认的MMM月份匹配规则 .appendText(ChronoField.MONTH_OF_YEAR, spanishMonthAbbrev) .appendLiteral('-') .appendValue(ChronoField.YEAR, 4) .toFormatter(new Locale("es", "ES")); return LocalDate.parse(fecha, formatter); }
注意:不要直接依赖默认的
LocalDate.parse()或不带配置的DateTimeFormatter.ofPattern()方法处理非标准格式的本地化日期字符串,这类场景下的默认规则都是面向严格标准格式设计的,很容易和现实中导出CSV的不规范格式出现匹配偏差。
内容的提问来源于stack exchange,提问作者Idea
相关产品推荐
相关产品推荐

