1

I am trying to parse the following string with LocalDate: "04 Aug 2015".

After trying a few variation of DateTimeFormatters, I looked for answers in SO and found out that some of the parsing examples given in answer did not work for me. After further investigation I have found out that java 14 fails to parse a date which include a string month such as "Jul", "Feb"... but in java 8 & 10 it worked flawlessly.

The Exception thrown was:

java.time.format.DateTimeParseException: Text '04 Aug 2015' could not be parsed at index 3

Have there been any changes to LocalDate/DateTimeFormatter in java 14? I could not find anything in the documentation.

Here is the code that prints successfully on java 8/10 and throws a DateTimeParseException at java 14:

  public static void main(String[] args) {
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd MMM yyyy");
    String anotherDate = "04 Aug 2015";
    LocalDate lds = LocalDate.parse(anotherDate, dtf);
    System.out.println(anotherDate + " , " + lds);
  }
Uri Loya
  • 1,181
  • 2
  • 13
  • 34
  • 2
    Works just fine for me. What is your default `Locale`? and are you sure this was working fine for you with Java-10 as well? – Naman Jul 21 '20 at 13:07
  • It also works fine for me. Is there an error it's throwing for you? – Tim Hunter Jul 21 '20 at 13:14
  • 1
    Thanks for checking, it seemed to be an issue with the locale. when I tried running it on java 10 it was on a different machine which probably had the correct locale. after trying rzwitserloot's answer it works – Uri Loya Jul 21 '20 at 13:22
  • 2
    Maybe stating the obvious, but this question/problem is ***unrelated to Java 14 (and `java-14`)***. Possibly you may want to consider to remove references to it from your question? Or update your question to make it clear in some other fashion? – Ivo Mori Jul 21 '20 at 13:46

1 Answers1

5

Turning 'Aug' into 'the 8th month' is not an easy job; most languages don't have 'Aug'.

the parser takes in a locale as part of the job, and it uses this amongst other things to translate (shortened) month names.

If you don't specify it, you get the system default, which can be problematic (because it can be different on every JVM you run this on).

My guess is that your JDK14 install is using a different default locale than your other installs.

Test it as follows:

System.out.println(java.util.Locale.getDefault());

and to fix your parse code:

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd MMM yyyy", Locale.ENGLISH);

NB: Whilst it is extremely common to see DTF.ofPattern("pattern"); in java code and in a million stack overflow examples, 99% of those lines of code are buggy - given that java is usually deployed on servers and/or this code is used to parse web traffic and not locally typed stuff, having the pattern use the system default locale is not correct.

Just like how you should almost never use, say, new FileWriter("filename"), instead using new FileWriter("filename", StandardCharsets.UTF_8);, you should almost never use DateTimeFormatter.ofPattern(pattern); - if your IDE has the ability to make a list of forbidden methods (methods for which a call MUST be accompanied by a comment explaining that you know what you're doing), you should add it.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • 3
    NB: The bevy of 'works for me' comments are precisely why methods like .ofPattern(pattern) are so nefarious. Tests don't catch this bug. – rzwitserloot Jul 21 '20 at 13:26
  • 1
    Very well explained answer, thank you. PS My guess is that 99 % is exaggerated; there are format pattern strings that do not contain any locale-sensitive elements, and so the one-arg `DateTimeFormatter.ofPattern(String)` is just fine. – Ole V.V. Jul 21 '20 at 15:05
  • 1
    @Ole and I'm sure you can rattle off, from memory, which ones those are. If you mess up, the penalty is a bug that you cannot find with a unit test. – rzwitserloot Jul 22 '20 at 01:02
  • I fully approve of your approach of specifying locale each time if just in case. It’s usually much simpler than running unit tests in all available locales. – Ole V.V. Jul 22 '20 at 03:00
  • I believe the line "If you don't specify it, you get the system default" is wrong. `ofPattern("dd/MMM/uu")` gives me an error whereas `ofPattern("dd/MMM/uu", Locale.getDefault())` does not. The default locale is `en_US`. – blackr1234 Nov 04 '21 at 08:52
  • 1
    It turns out that the system default used by `DateTimeFormatter` is specified in `DateTimeFormatterBuilder`, which is actually the default locale of the `Locale.Category.FORMAT` category, not `Locale.getDefault()` but `Locale.getDefault(Locale.Category.FORMAT)`. – blackr1234 Nov 04 '21 at 14:00