Hello I'm here for a DateTimeFormatter problem with the Locale formatter language, let me introduce you:
Observed error with stack trace:
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)
Minimal, reproducible code example:
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;
}
I've got the same error trying different things and methods from locale and DateTimeFormatter don't even know what i was doing, but I think that this should work OBVIOUSLY NOT.
In the other answer geocodezip has already explained why your attempt failed. Here are two suggestions for solutions that I find more elegant than the one in that answer.
Java can get its locale data including month abbreviations in different languages from up to four sources. Since Java 9 by default it prefers to get them from CLDR, the Unicode Common Locale Data Repository. In CLDR Spanish month abbreviations are with a dot (or full point) as explained in the other answer, like dic.
for diciembre. Another source is the locale data that were built-in with Java since the early versions (and were the default until Java 8). Here Spanish month abbreviations haven’t got dots (and your data may have been produced by a program running on Java 8 or earlier, I cannot know). These locale data are referred to as COMPAT
for compatible with earlier Java versions. When you launch your program, you can specify on the command line that Java should prefer COMPAT over CLDR, for example:
java -Djava.locale.providers=COMPAT,CLDR YourJavaMainClass
This will cause your existing code to accept dic
and other month abbreviations without dot.
It’s a global setting for the JVM, so it will also cause any locale-sensitive operation anywhere in your program and in other programs running in the same JVM to use the old locale data from Java 8. Think twice.
Since you know that your format is always 28-dic-2017
, you may also make yourself completely independent of any locale data simply by specifying explicitly which month abbreviations are used in your input data.
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();
This formatter is independent of locale and parses your date string:
String fecha = "28-dic-2017";
LocalDate date = LocalDate.parse(fecha, inputDateFormatter);
System.out.println(date);
Output is:
2017-12-28
A tip: when parsing doesn’t work, you may try formatting first to get to know how the string to be parsed was supposed to look like and compare to the string that you were trying to parse. For example:
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));
Want to parse: 28-dic-2017 Formatted: 28-dic.-2017 Want to parse: 29-sep-2017 Formatted: 29-sept.-2017
Now we can at least see what is wrong for a start.
LocaleServiceProvider
listing the possible sources of locale data in JavaDateTimeFormatterBuilder.appendText(TemporalField, Map)