无法在Java中从西班牙语日期字符串转换为LocalDate

无法在Java中从西班牙语日期字符串转换为LocalDate,java,datetime,java-8,setlocale,datetimeformatter,Java,Datetime,Java 8,Setlocale,Datetimeformatter,您好,我是来解决区域设置格式化程序语言的DateTimeFormatter问题的,让我向您介绍: 我正在读取以下字符串格式的CSV文件:“dd-MMM-yyyy”“28-dic-2017” 然后,我必须将列表中的每个字符串解析为LocalDate,以使用timeAPI方法处理每个字符串 请注意,我有几个月的西班牙语课程。真是一团糟 执行时返回: 观察到堆栈跟踪错误: Exception in thread "main" java.time.format.DateTimeP

您好,我是来解决区域设置格式化程序语言的DateTimeFormatter问题的,让我向您介绍:

  • 我正在读取以下字符串格式的CSV文件:“dd-MMM-yyyy”“28-dic-2017”
  • 然后,我必须将列表中的每个字符串解析为LocalDate,以使用timeAPI方法处理每个字符串
  • 请注意,我有几个月的西班牙语课程。真是一团糟
  • 执行时返回:
观察到堆栈跟踪错误:

Exception in thread "main" java.time.format.DateTimeParseException: Text '28-dic-2017' could not be parsed at index 3
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2051)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1953)
    at java.base/java.time.LocalDate.parse(LocalDate.java:429)
    at com.examen.Presentation.Principal.parseDate(Principal.java:28)
    at com.examen.Presentation.Principal.main(Principal.java:19)
最小、可复制的代码示例:

public static LocalDate parseDate(String fecha) {

    Locale loc = new Locale("es", "ES");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy", loc);
    LocalDate date = LocalDate.parse(fecha, formatter);

    return date;
}

我从locale和DateTimeFormatter尝试不同的事情和方法时遇到了相同的错误,我甚至不知道我在做什么,但我认为这显然不起作用。

对于西班牙语,
DateTimeFormatter
希望缩短的月份以一个句点结束。像这样:
28 dic.-2017

如果所有日期都是该格式,则可以解析输入字符串以添加句点,然后将其发送到
DateTimeFormatter

public static LocalDate parseDate(String fecha) {
    int firstDash = fecha.indexOf('-')+1;
    int secondDash = fecha.indexOf('-', fecha.indexOf('-')+1);
    String month = fecha.substring(firstDash, secondDash);
    String dateStr = fecha.substring(0,firstDash)+month+"."+fecha.substring(secondDash);
    Locale loc = new Locale("es", "ES");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy", loc);
    LocalDate date = LocalDate.parse(dateStr, formatter);

    return date;
}
如果格式有时有句点,则需要添加句点(如果它不存在):

public static LocalDate parseDate(String fecha) {
    String dateStr;
    if (fecha.indexOf(".")!=-1) {
        dateStr = fecha;
    } else {
        int firstDash = fecha.indexOf('-')+1;
        int secondDash = fecha.indexOf('-', fecha.indexOf('-')+1);
        String month = fecha.substring(firstDash, secondDash);
        dateStr = fecha.substring(0,firstDash)+month+"."+fecha.substring(secondDash);
    }
    System.out.println(dateStr);
    Locale loc = new Locale("es", "ES");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy", loc);
    LocalDate date = LocalDate.parse(dateStr, formatter);

    return date;
}
输出:

2017-12-28


对于西班牙语,
DateTimeFormatter
希望缩短的月份以句点结束。像这样:
28 dic.-2017

如果所有日期都是该格式,则可以解析输入字符串以添加句点,然后将其发送到
DateTimeFormatter

public static LocalDate parseDate(String fecha) {
    int firstDash = fecha.indexOf('-')+1;
    int secondDash = fecha.indexOf('-', fecha.indexOf('-')+1);
    String month = fecha.substring(firstDash, secondDash);
    String dateStr = fecha.substring(0,firstDash)+month+"."+fecha.substring(secondDash);
    Locale loc = new Locale("es", "ES");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy", loc);
    LocalDate date = LocalDate.parse(dateStr, formatter);

    return date;
}
如果格式有时有句点,则需要添加句点(如果它不存在):

public static LocalDate parseDate(String fecha) {
    String dateStr;
    if (fecha.indexOf(".")!=-1) {
        dateStr = fecha;
    } else {
        int firstDash = fecha.indexOf('-')+1;
        int secondDash = fecha.indexOf('-', fecha.indexOf('-')+1);
        String month = fecha.substring(firstDash, secondDash);
        dateStr = fecha.substring(0,firstDash)+month+"."+fecha.substring(secondDash);
    }
    System.out.println(dateStr);
    Locale loc = new Locale("es", "ES");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy", loc);
    LocalDate date = LocalDate.parse(dateStr, formatter);

    return date;
}
输出:

2017-12-28


在另一个答案中,geocodezip已经解释了您的尝试失败的原因。这里有两个解决方案的建议,我觉得比答案中的建议更优雅

Java语言环境数据提供程序 Java最多可以从四个来源获得不同语言的语言环境数据,包括月份缩写。由于默认情况下Java9更喜欢从CLDR(Unicode公共语言环境数据存储库)获取它们。在CLDR西班牙语中,月份缩写带有一个点(或满点),如另一个答案中所述,如diciembre的
dic.
。另一个来源是Java自早期版本以来内置的语言环境数据(在Java8之前是默认的)。这里的西班牙语月份缩写没有点(您的数据可能是由运行Java8或更早版本的程序生成的,我不知道)。这些区域设置数据称为
COMPAT
,以便与早期Java版本兼容。启动程序时,您可以在命令行上指定Java应该更喜欢COMPAT而不是CLDR,例如:

java -Djava.locale.providers=COMPAT,CLDR YourJavaMainClass
    Locale loc = new Locale("es", "ES");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy", loc);
    
    System.out.println("Want to parse: 28-dic-2017");
    System.out.println("Formatted:     "
            + LocalDate.of(2017, Month.DECEMBER, 28).format(formatter));
    System.out.println("Want to parse: 29-sep-2017");
    System.out.println("Formatted:     "
            + LocalDate.of(2017, Month.SEPTEMBER, 29).format(formatter));
这将导致您的现有代码接受
dic
和其他没有dot的月份缩写

它是JVM的一个全局设置,因此它还将导致程序中任何地方以及在同一JVM中运行的其他程序中的任何对区域设置敏感的操作使用来自Java8的旧区域设置数据。三思而后行

DateTimeFormatterBuilder.appendText() 由于您知道您的格式始终为
28-dic-2017
,您也可以通过明确指定输入数据中使用的月份缩写,使自己完全独立于任何语言环境数据

private static Map<Long, String> getMonthAbbreviations() {
    return Map.ofEntries(
            Map.entry(1L, "ene"),
            Map.entry(2L, "feb"),
            Map.entry(3L, "mar"),
            Map.entry(4L, "abr"),
            Map.entry(5L, "may"),
            Map.entry(6L, "jun"),
            Map.entry(7L, "jul"),
            Map.entry(8L, "ago"),
            Map.entry(9L, "sep"),
            Map.entry(10L, "oct"),
            Map.entry(11L, "nov"),
            Map.entry(12L, "dic"));
}

private static final DateTimeFormatter inputDateFormatter = new DateTimeFormatterBuilder()
        .appendPattern("dd-")
        .appendText(ChronoField.MONTH_OF_YEAR, getMonthAbbreviations())
        .appendPattern("-uuuu")
        .toFormatter();
输出为:

2017-12-28

解析问题的提示:首先尝试格式化 提示:当解析不起作用时,您可以先尝试格式化,以了解要解析的字符串的外观,并与您尝试解析的字符串进行比较。例如:

java -Djava.locale.providers=COMPAT,CLDR YourJavaMainClass
    Locale loc = new Locale("es", "ES");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy", loc);
    
    System.out.println("Want to parse: 28-dic-2017");
    System.out.println("Formatted:     "
            + LocalDate.of(2017, Month.DECEMBER, 28).format(formatter));
    System.out.println("Want to parse: 29-sep-2017");
    System.out.println("Formatted:     "
            + LocalDate.of(2017, Month.SEPTEMBER, 29).format(formatter));
现在我们至少可以从一开始就看出什么是错误的

文档链接
  • 列出Java语言环境数据的可能来源

在另一个答案中,geocodezip已经解释了您的尝试失败的原因。这里有两个解决方案的建议,我觉得比答案中的建议更优雅

Java语言环境数据提供程序 Java最多可以从四个来源获得不同语言的语言环境数据,包括月份缩写。由于默认情况下Java9更喜欢从CLDR(Unicode公共语言环境数据存储库)获取它们。在CLDR西班牙语中,月份缩写带有一个点(或满点),如另一个答案中所述,如diciembre的
dic.
。另一个来源是Java自早期版本以来内置的语言环境数据(在Java8之前是默认的)。这里的西班牙语月份缩写没有点(您的数据可能是由运行Java8或更早版本的程序生成的,我不知道)。这些区域设置数据称为
COMPAT
,以便与早期Java版本兼容。启动程序时,您可以在命令行上指定Java应该更喜欢COMPAT而不是CLDR,例如:

java -Djava.locale.providers=COMPAT,CLDR YourJavaMainClass
    Locale loc = new Locale("es", "ES");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy", loc);
    
    System.out.println("Want to parse: 28-dic-2017");
    System.out.println("Formatted:     "
            + LocalDate.of(2017, Month.DECEMBER, 28).format(formatter));
    System.out.println("Want to parse: 29-sep-2017");
    System.out.println("Formatted:     "
            + LocalDate.of(2017, Month.SEPTEMBER, 29).format(formatter));
这将导致您的现有代码接受
dic
和其他没有dot的月份缩写

它是JVM的一个全局设置,因此它还将导致程序中任何地方以及在同一JVM中运行的其他程序中的任何对区域设置敏感的操作使用来自Java8的旧区域设置数据。三思而后行

DateTimeFormatterBuilder.appendText() 由于您知道您的格式始终为
28-dic-2017
,您也可以通过明确指定输入数据中使用的月份缩写,使自己完全独立于任何语言环境数据

private static Map<Long, String> getMonthAbbreviations() {
    return Map.ofEntries(
            Map.entry(1L, "ene"),
            Map.entry(2L, "feb"),
            Map.entry(3L, "mar"),
            Map.entry(4L, "abr"),
            Map.entry(5L, "may"),
            Map.entry(6L, "jun"),
            Map.entry(7L, "jul"),
            Map.entry(8L, "ago"),
            Map.entry(9L, "sep"),
            Map.entry(10L, "oct"),
            Map.entry(11L, "nov"),
            Map.entry(12L, "dic"));
}

private static final DateTimeFormatter inputDateFormatter = new DateTimeFormatterBuilder()
        .appendPattern("dd-")
        .appendText(ChronoField.MONTH_OF_YEAR, getMonthAbbreviations())
        .appendPattern("-uuuu")
        .toFormatter();
输出为:

2017-12-28

解析问题的提示:首先尝试格式化 提示:当解析不起作用时,您可以先尝试格式化,以了解要解析的字符串的外观,并与您尝试解析的字符串进行比较。例如:

java -Djava.locale.providers=COMPAT,CLDR YourJavaMainClass
    Locale loc = new Locale("es", "ES");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy", loc);
    
    System.out.println("Want to parse: 28-dic-2017");
    System.out.println("Formatted:     "
            + LocalDate.of(2017, Month.DECEMBER, 28).format(formatter));
    System.out.println("Want to parse: 29-sep-2017");
    System.out.println("Formatted:     "
            + LocalDate.of(2017, Month.SEPTEMBER, 29).format(formatter));
现在我们至少可以从一开始就看出什么是错误的

文档链接
  • 列出Java语言环境数据的可能来源

非常感谢您抽出时间!!我首先测试了您的解决方案,但正如OLEV.V.所说,我使用的是Java8,我得到了相同的结果