I have some old Java code that attempts to parse a string using SimpleDateFormat
. It is frequently throwing a ParseException
:
Non-fatal Exception: java.text.ParseException:
Unparseable date: "06:00:00 PM" at java.text.DateFormat.parse(DateFormat.java:400)
I can't see what is going wrong here. Seems simple. Hoping somebody can spot it.
public static String toTimeString(String time, String inTimeFormat, String outTimeFormat) {
DateFormat df1 = new SimpleDateFormat(inTimeFormat, Locale.getDefault());
DateFormat df2 = new SimpleDateFormat(outTimeFormat, Locale.getDefault());
String timeString = "";
try {
Date date = df1.parse(time); //<-- exception thrown here
_12HrTime = df2.format(date);
} catch (ParseException e) {
Crashlytics.recordException(e);
}
return timeString;
}
Here is how it is being called when it fails:
toTimeString("06:00:00 PM", "hh:mm:ss a", "h:mm a")
Note that the string 06:00:00 PM
comes from a server response.
Every time I run this, it works correctly. But Crashlytics reports this error frequently. What am I missing??
Specify Locale
to be used in parsing localized text PM
.
Use modern java.time classes, not legacy classes. Specifically java.time.LocalTime
.
LocalTime
.parse(
"06:00:00 PM" ,
DateTimeFormatter
.ofPattern( "hh:mm:ss a" )
.withLocale( Locale.of( "en" , "US" ) ) // ⬅️ Specify locale to be used in parsing localized text `PM`.
)
You are using terribly flawed legacy classes that were years ago supplanted by the modern java.time classes defined in JSR 310.
LocalTime
And you are attempting to represent a time-of-day value with a class that represents a date with time-of-day — square peg in a round hole. Instead use the appropriate class: LocalTime
.
Locale
Specify a Locale
to determine the human language and cultural norms to be used in parsing the localized PM
. Some cultures use lowercase, pm
, some use punctuation, p.m.
. And some use entirely different text.
If you omit the locale, the JVM’s current default locale will be used implicitly. That particular locale may not be able to make sense of your text PM
.
String input = "06:00:00 PM" ;
Locale locale = Locale.of( "en" , "US" ) ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "hh:mm:ss a" ).withLocale( locale ) ;
LocalTime time = LocalTime.parse( input , f ) ;
See an older version of this code run at Ideone.com.
time.toString() = 18:00
Android 26+ bundles an implementation of the java.time classes. For earlier Android, the latest tooling provides most of the functionality via “API desugaring”.
Tip: Avoid using localized text when exchanging/storing date-time values. Use only ISO 8601 standard values.
For a time-of-day that would be 24-hour clock, with zero seconds being optional, with leading & trailing padded zeros. So, 18:00
for 6 PM.