java.text.ParseException: Unparseable date
Asked Answered
T

3

9

I get the following error: ´java.text.ParseException: Unparseable date: "Aug 31 09:53:19 2011"´ with this format: new SimpleDateFormat("MMM dd HH:mm:ss yyyy");

Does anyone see the problem?

Thornhill answered 31/8, 2011 at 8:17 Comment(3)
Looks fine to me. Make sure you're using the SimpleDateFormat object you created with the shown code to actually parse the given date.Pantheism
Big tip: Always specify explicitly both the Locale and the time zone in your date-time work rather than rely implicitly on the JVM’s current default. Both can change at any moment during runtime.Hooked
FYI, the troublesome old date-time classes such as java.util.Date, java.util.Calendar, and java.text.SimpleDateFormat are now legacy, supplanted by the java.time classes built into Java 8 and later. See Tutorial by Oracle.Hooked
O
27

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.)

Overwind answered 31/8, 2011 at 8:22 Comment(3)
Thanks for the tip! This bug was tripping me up, too.Lulu
This fixes the problem, but why? what is changed when the locale is french??Norikonorina
the month name - Aug would instead become aoûtKlemens
I
7

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");
Ifc answered 31/8, 2011 at 8:23 Comment(8)
I have date like this 2017-08-01T08:32:38.5544401-05:00 and this is the pattern yyyy-MM-dd'T'HH:mm:ssz. and i'm getting the exception. Please helpPolitian
@eCDroid your date does not match the pattern; there are fractional seconds in the date string, which are not in the pattern. Use the correct pattern.Ifc
you mean ss.sssssss?Politian
@eCDroid No, it's a bit more complicated because SimpleDateFormat cannot deal with 7 digits of fractional seconds. See: #12001173Ifc
I tried this String actualFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSSz"; and this is the result Orignal Date: 2017-08-01T08:50:36.8762641-05:00 Converted Time: 18:50:36 Is it correct?Politian
@eCDroid See the question I linked to.Ifc
Did you observer in my case i have seconds in decimal value no millis 08:50:36.8762641 this figure 36.8762641?Politian
I successfully achieve it by making the pattern to yyyy-MM-dd'T'HH:mm:ssPolitian
H
5

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?

Hooked answered 17/8, 2015 at 22:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.