java.text.ParseException: Unparseable date
Make sure you're using the correct locale. (The SimpleDateFormat(String)
constructor uses the system default locale, which may not be the one you want to use.)
This works fine on my machine:
String input = "Aug 31 09:53:19 2011";
DateFormat df = new SimpleDateFormat("MMM dd HH:mm:ss yyyy", Locale.US);
System.out.println(df.parseObject(input));
(While using Locale.FRENCH
for instance, results in a ParseException
.)
The format itself is OK for the input you gave. But you might get this error if your default locale is set to something where "Aug" is not a valid abbreviation of a month name. Try using for example to Locale.US
and you'll see that it will work:
DateFormat df = new SimpleDateFormat("MMM dd HH:mm:ss yyyy", Locale.US);
Date date = df.parse("Aug 31 09:53:19 2011");
tl;dr
- Specify the
Locale
, to determine human language and cultural norms used in translating the name of month. - Use modern java.time classes rather that troublesome legacy classes.
Contrived example:
LocalDateTime.parse( // Parse input text as a `LocalDateTime` lacking any concept of time zone or offset-from-UTC.
"Aug 31 09:53:19 2011" ,
DateTimeFormatter.ofPattern( "MMM dd HH:mm:ss yyyy" ) // Specify formatting pattern to match input string.
.withLocale( Locale.US ) // The `Locale` determines the human language and cultural norms used in translating the input text.
) // Returns a `LocalDateTime` object.
Details
The other two answers by aioobe and by Jesper are both correct: Implicitly using a Locale
with a human language that does not match the language of your input text.
This Answer explains a new way of doing the job. Also, the other Answers do not address the crucial issue of time zone.
java.time
Fast forward a few years later from this posting, and we now have the new java.time package built into Java 8 and later. These new classes supplant the old java.util.Date/.Calendar & SimpleDateFormat classes. Those old classes have proven to be troublesome, confusing, and flawed.
Formatter Pattern
Define the data to be parsed and its format.
String input = "Aug 31 09:53:19 2011";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "MMM dd HH:mm:ss uuuu" );
If not specified, the DateTimeFormatter
is assigned the Locale
that is currently the default in the JVM. That default can change at any moment, even during runtime(!). So always specify the desired/expected Locale
.
formatter = formatter.withLocale( Locale.US ); // Or Locale.UK, Locale.CANADA_FRENCH, etc.
Given that the input lacks any time zone or offset-from-UTC information, parse as a LocalDateTime
.
LocalDateTime ldt = LocalDateTime.parse( input , formatter );
If from the context you know the intended offset-from-UTC or a time zone for this date-time value, assign it.
If UTC, use the ZoneOffset.UTC
constant to get a OffsetDateTime
object.
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC );
A time zone is an offset-from-UTC plus a set of rules for handling anomalies such as Daylight Saving Time (DST). Use proper time zone names, never the 3-4 letter abbreviations.
ZoneId zoneId_Montreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ldt.atZone( zoneId_Montreal );
Specify Time Zone
This human language element was the key missing piece to answer the Question. Specifying the correct Locale
for the human language matching the language of your input string solves that problem.
But note that the time zone is also critical; the other answers ignored this issue thereby implicitly using the JVM’s current default time zone. That is not advisable, as it depends on the host operating system as an initial default value (so may vary) and furthermore any code in any thread of any app within the JVM can change the JVM’s current default time zone during runtime. Better to specify the desired/expected time zone than rely implicitly on default.
Immutable Objects
Note the syntax. These classes are designed to be immutable. So rather than modifying (mutating) an object, a fresh new object is created based on the old object’s values. This means we are not affecting the DateTimeFormatter
object defined above and held in the formatter
variable (object reference). We are creating, using, and discarding a new DateTimeFormatter object (actually, two new objects) within this line of code.
Method Reference
The documentation suggests an alternative way to parse a string is to call the parse
method where you pass a method reference (new in Java 8) from the class of the kind of result you desire (as the TemporalQuery
): ZonedDateTime::from
, LocalDateTime::from
, LocalDate::from
, and so on.
ZonedDateTime zdt = formatter.withZone( zoneId_Montreal ).withLocale( Locale.ENGLISH ).parse( input, ZonedDateTime :: from );
For demonstration, let's turn around and create a String representation of that ZonedDateTime
value but in Québécois French.
String output = formatter.withLocale( Locale.CANADA_FRENCH ).format( zdt );
Even better, let’s localize rather than hard-code a particular format.
String outputLocalized = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ).format( zdt );
Dump to console.
System.out.println( "input: " + input );
System.out.println( "formatter: " + formatter );
System.out.println( "zdt: " + zdt );
System.out.println( "output: " + output );
System.out.println( "outputLocalized: " + outputLocalized );
When run.
input: Aug 31 09:53:19 2011
formatter: Text(MonthOfYear,SHORT)' 'Value(DayOfMonth,2)' 'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)' 'Value(YearOfEra,4,19,EXCEEDS_PAD)
zdt: 2011-08-31T09:53:19-04:00[America/Montreal]
output: août 31 09:53:19 2011
outputLocalized: mercredi 31 août 2011 9 h 53 EDT
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
- Java SE 8, Java SE 9, Java SE 10, and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and Java SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….