1

Why this code give me an Exception?

String myFormat = "dd MMMMM uuuu";
String dateToFormat = "26 Mai 2010";
DateTimeFormatter myFormatter = new DateTimeFormatterBuilder().appendPattern(myFormat)
            .toFormatter().withResolverStyle(ResolverStyle.STRICT);
LocalDate myDate=LocalDate.parse(dateToFormat,myFormatter);

Exception:

java.time.format.DateTimeParseException: Text '26 Mai 2010' could not be parsed at index 4
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
    at java.time.LocalDate.parse(LocalDate.java:400)

If I try with 'MMMM' instead of 'MMMMM' than it works as expected.

String myFormat = "dd MMMM uuuu";
Neo
  • 1,337
  • 4
  • 21
  • 50
  • Is there a date format like dd MMMMM uuuu – mstfyldz Mar 08 '19 at 13:46
  • 1
    Locale is important here. We will not be able to reproduce unless you tell us what your default Locale is. ('Mai' will *never* parse for me, because my default Locale is UK, where the month is called 'May') – Michael Mar 08 '19 at 13:47
  • 1
    “Exactly 5 pattern letters will use the narrow form.” From [the documentation](https://docs.oracle.com/javase/9/docs/api/java/time/format/DateTimeFormatter.html). Seems that the narrow form of `Mai` is `M` in your language. So it objects to the letter `a` coming where it had expected the space after the month. (So yes, @mstfyldz, there is.) – Ole V.V. Mar 08 '19 at 13:57
  • does it work if you use May instead of Mai? – Brent Sandstrom Mar 08 '19 at 14:00

1 Answers1

5

As the javadoc of DateTimeFormatter explains, and I quote: Exactly 4 pattern letters will use the full form. Exactly 5 pattern letters will use the narrow form.

I don't know why either; narrow forms are actually very very short, presumably for months it'd be the first letter, which is extremely useless, as for example both june and july start with a J (even in german). The easiest way to figure this kind of thing out is to go in reverse: Take a known date and use .format instead of .parse to see what it looks like.

What you want is 4x the letter M, which is the complete name of the month.

As a few comments have said, how it functions exactly will depend on your system locale which makes testing and advice much harder than it needs to be. Generally, you should always explicitly choose a locale. You can call the withLocale method to force it.

Here's some sample code to play with:

import java.time.*; import java.time.format.*; import java.util.*;

public class Test {
    public static void main(String[] args) {
        String myFormatNarrow = "dd MMMMM uuuu";
        String myFormatFull = "dd MMMM uuuu";
        String dateToFormat = "26 Juni 2010";
        String dateToFormat2 = "26 J 2010";
        String dateToFormat3 = "26 Jun 2010";
        DateTimeFormatter myFormatter;
        LocalDate myDate;
        myFormatter = new DateTimeFormatterBuilder().appendPattern(myFormatFull)
                    .toFormatter().withResolverStyle(ResolverStyle.STRICT).withLocale(Locale.GERMAN);
        System.out.println("FULL: " + myFormatter.format(LocalDate.of(2010, 6, 26)));
        myDate = LocalDate.parse(dateToFormat, myFormatter);
        System.out.println("PARSED: " + myDate);
        myFormatter = new DateTimeFormatterBuilder().appendPattern(myFormatNarrow)
                    .toFormatter().withResolverStyle(ResolverStyle.STRICT).withLocale(Locale.GERMAN);
        System.out.println("NARROW: " + myFormatter.format(LocalDate.of(2010, 6, 26)));
        myDate = LocalDate.parse(dateToFormat2, myFormatter);
        // It parses a single J as 'july'. Clearly showing why narrow-form is useless here.
        System.out.println("PARSED: " + myDate);
        // note that even ResolverStyle.LENIENT can't do it either; this will fail:
        myFormatter = myFormatter.withResolverStyle(ResolverStyle.LENIENT);
    //   myDate = LocalDate.parse(dateToFormat3, myFormatter);
    // System.out.println("PARSED: " + myDate);
    }
}
rzwitserloot
  • 85,357
  • 5
  • 51
  • 72