I have a confusing problem, consider this working code:
package com.mycompany.mavenproject2;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Main {
public static void main(String[] args) throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
Date date = formatter.parse("01-Jan-2017 00:47:13");
System.out.println(date);
}
}
which prints Sun Jan 01 00:47:13 CET 2017
when executing as expected.
However, when I replace each -
with a .
dot in the date:
package com.mycompany.mavenproject2;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Main {
public static void main(String[] args) throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat("dd.MMM.yyyy HH:mm:ss");
Date date = formatter.parse("01.Jan.2017 00:47:13");
System.out.println(date);
}
}
The code throws an exception on execution:
Exception in thread "main" java.text.ParseException: Unparseable date: "01.Jan.2017 00:47:13"
at java.base/java.text.DateFormat.parse(DateFormat.java:395)
at com.mycompany.mavenproject2.Main.main(Main.java:11)
I am using Java version 12 and German locale.
Has someone got an idea?
I strongly agree with the comments recommending java.time, the modern Java date and time API, for your date and time work.
Use this formatter:
private static final DateTimeFormatter FORMATTER
= DateTimeFormatter.ofPattern("dd.MMMuuuu HH:mm:ss", Locale.GERMAN);
Do:
LocalDateTime dateTime = LocalDateTime.parse("01.Jan.2017 00:47:13", FORMATTER);
System.out.println(dateTime);
Output when run on Java 11 with German locale:
2017-01-01T00:47:13
You may wonder why compared to your format pattern string I have left out the second dot? On Java 11 (and probably near Java versions too, possibly from Java 9 through 16) German month abbreviations are with a dot to signify abbreviation, so Jan.
for Januar (January), etc. So in my format MMM
matches Jan.
and then uuuu
matches 2017.
For the fuller story Java gets its locale data including the month abbreviations used in different locales from up to four sources, and not all sources agree what German month abbreviations look like. Since Java 9 the default is CLDR,COMPAT
meaning that locale data from CLDR, the Unicode Common Locale Data Repository, are preferred. And these include the dots I menitoned. You can get different results by setting the system property java.locale-providers
to a value that does not begin with CLDR
.
I have given you a hint already: In some Java versions German month abbreviations are with a dot. So in your example with dots as separators your SimpleDateFormat
matched dd.MMM
(without the second dot) to 01.Jan.
(with the second dot). According to the format a dot should now come, but since that dot had already been consumed, SimpleDateFOrmat
looked at 2017
, decided it wasn’t a dot and threw the exception that you saw.
The really surprising behaviour was in your first example where SimpleDateFormat
was able to parse 01-Jan-2017 00:47:13
without any dots even though it believes that the month abbreviation should end in a dot. I have seen literally hundreds of examples of surprising behaviour of SimpleDateFormat
before, but never any akin to this one.
And all of these surprises are what make me say: By all means avoid using SimpleDateFormat
.
If you’re skeptical, I don’t blame you. So to demonstrate:
SimpleDateFormat formatter = new SimpleDateFormat("MMMyyyy", Locale.GERMAN);
System.out.println(formatter.format(0L));
System.out.println(formatter.parse("Jan2017"));
System.out.println(formatter.parse("Jan.2017"));
Output, still on Java 11:
Jan.1970 Sun Jan 01 00:00:00 CET 2017 Sun Jan 01 00:00:00 CET 2017
We see that SimpleDateFormat
formats the month with a dot, and is able to parse strings both with and without dots.
This still isn’t the full story.
SimpleDateFormat formatter = new SimpleDateFormat("MMM", Locale.GERMAN);
System.out.println(formatter.format(0L));
Output:
Jan
This time the month abbreviation was formatted without the dot. I got no idea what is going on. I repeat, forget about the confusing SimpleDateFormat
class. It’s a notorious troublemaker.