Java 11出现DateTimeParseException但Java 8/18正常的解决咨询
Java 11下解析西班牙格式日期失败的解决方案
问题说明
代码在Java 8、Java 18环境可正常运行,但在Java 11.0.19 LTS中执行时抛出DateTimeParseException,无法解析日期字符串24ENE1982。尝试使用Locale.forLanguageTag("es-ES")和new Locale("es", "ES")指定西班牙区域均无效,期望输出为Hello world! 1982-01-24。
代码示例
public class Main { public static void main(String[] args) { LocalDate date = LocalDate.parse("24ENE1982", new DateTimeFormatterBuilder().parseCaseInsensitive() .appendPattern("ddMMMyyyy") .toFormatter(new Locale("es", "ES"))); System.out.println("Hello world! " + date); } }
异常信息
Exception in thread "main" java.time.format.DateTimeParseException: Text '24ENE1982' could not be parsed at index 2 at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046) at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948) at java.base/java.time.LocalDate.parse(LocalDate.java:428) at Main.main(Main.java:7)
问题原因
Oracle JDK 11开始默认采用CLDR(Unicode通用区域数据仓库)作为区域数据来源,而Java 8使用的是旧版JRE区域数据。两者对西班牙文月份缩写的定义存在差异:CLDR中西班牙文一月的标准缩写为全小写的ene,且默认的大小写不敏感解析未兼容这种差异,导致无法匹配大写的ENE。
解决方案
方案1:修改JVM启动参数(兼容Java 8行为)
启动JVM时添加参数,优先使用旧版兼容模式的区域数据:
-Djava.locale.providers=COMPAT,CLDR
此方案无需修改代码,直接让Java 11的区域数据行为和Java 8保持一致。
方案2:代码中自定义月份映射(无需修改JVM参数)
手动定义西班牙月份的缩写映射,确保解析时能匹配大小写:
import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.ChronoField; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { // 定义西班牙月份的缩写(支持大小写匹配) Map<Long, String> monthAbbrMap = new HashMap<>(); monthAbbrMap.put(1L, "ENE"); monthAbbrMap.put(2L, "FEB"); monthAbbrMap.put(3L, "MAR"); monthAbbrMap.put(4L, "ABR"); monthAbbrMap.put(5L, "MAY"); monthAbbrMap.put(6L, "JUN"); monthAbbrMap.put(7L, "JUL"); monthAbbrMap.put(8L, "AGO"); monthAbbrMap.put(9L, "SEP"); monthAbbrMap.put(10L, "OCT"); monthAbbrMap.put(11L, "NOV"); monthAbbrMap.put(12L, "DIC"); DateTimeFormatter formatter = new DateTimeFormatterBuilder() .parseCaseInsensitive() .appendPattern("dd") // 绑定自定义的月份解析规则 .appendText(ChronoField.MONTH_OF_YEAR, monthAbbrMap) .appendPattern("yyyy") .toFormatter(); LocalDate date = LocalDate.parse("24ENE1982", formatter); System.out.println("Hello world! " + date); } }
该方案通过硬编码月份映射,完全控制解析逻辑,不依赖系统区域设置,兼容性更强。
内容的提问来源于stack exchange,提问作者aconsuegra
相关产品推荐
相关产品推荐

