Getting error java.text.ParseException: Unparseable date: (at offset 0) even if the Simple date format and string value are identical
I'm always getting the parse exception even if the format to check and the string value are same. Here is the code:
String format = "EEE MMM dd HH:mm:ss z yyyy";
String value = "Mon Sep 18 10:30:06 MST 2017";
public static boolean isValidFormat(String format, String value) {
Date date = null;
try {
SimpleDateFormat sdf = new SimpleDateFormat(format);
date = sdf.parse(value); // here it breaks
if (!value.equals(sdf.format(date))) {
date = null;
}
} catch (ParseException ex) {
ex.printStackTrace(); //java.text.ParseException: Unparseable date:
"Mon Sep 18 10:30:06 MST 2017" (at offset 0)
}
return date != null;
}
It says that your date-time string is unparseable at index 0. Index 0 is where it says Mon
, so the three letter time zone abbreviation is not the first suspect. The locale is. “Mon” works as abbreviation for Monday in English, but not in very many other languages. So if your device has a non-English language setting — maybe it has even been changed recently — this will fully explain your observation.
The shortsighted solution is
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.ROOT);
I use Locale.ROOT
to mean that no language specific processing should be done. If your string is in English because English is generally the language used in computing around the globe, I would consider this choice appropriate. If on the other hand it is in English because it comes from an English speaking locale, that locale will be the right one to use.
With this change, on my computer your code formats your date into Mon Sep 18 11:30:06 MDT 2017
, which, as you can see is not the same as the value we started out from, so your method returns false. My JVM understood MST as Mountain Standard Time, and then assumed summer time (DST) in September and formatted the string accordingly.
ThreeTenABP
That said, Date
and SimpleDateFormat
are long outdated classes. You should give it a thought to get rid of them and use the modern Java date and time API instead. On Android you get it in the ThreeTenABP, see this question: How to use ThreeTenABP in Android Project. Now you may do:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format, Locale.ROOT);
try {
return ZonedDateTime.parse(value, dtf).format(dtf).equals(value);
} catch (DateTimeParseException dtpe) {
dtpe.printStackTrace();
return false;
}
This behaves the same as above.
Three letter time zone abbreviations
You should avoid the three and four letter time zone abbreviations where you can. They are not standardized and generally ambiguous. MST, for example, may mean Malaysia Standard Time or Mountain Standard Time. The latter isn’t even a full time zone, since MDT is used for the greater part of the year, which caused the trouble I observed as I said above.
Instead, see if you can get a string in ISO 8601 format, like 2017-09-18T10:30:06+08:00
. Second best, just get something unambiguous. One way is to include an offset from UTC rather than a time zone ID (or both).