I\'m trying to parse a String to a Date Object, as part of a loading functionality for my program, as seen below:
String dateString = \"Wed Jan 18 23:22:18 E
TL;DR: the newer DateTimeFormatter
and friends are somewhat more helpful in debugging issues like yours compared to the outdated SimpleDateFormat
.
This is not the answer you were asking for, but it may be the answer you want. If there is any way you can (which there is), drop the outdated classes SimpleDateFormat
and Date
in favour of the modern ones in the java.time
package. The way to do in your case isn’t much different from your code. PLEASE NOTE: I am deliberately including your error.
String dateString = "Wed Jan 18 23:22:18 EST 2017";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd hh:mm:ss zzz YYYY"); // wrong
try {
ZonedDateTime scheduleItemDate = ZonedDateTime.parse(dateString, dtf);
System.out.println(scheduleItemDate.toString());
}
catch (DateTimeParseException e) {
System.out.println("Exception");
}
The output is different, though: the above snippet prints
Exception
I am serious when I say I consider this an improvement. There was a bug in your program all the time, and now the program tells you there is bug. On my computer, the exception message I get is
Text 'Wed Jan 18 23:22:18 EST 2017' could not be parsed at index 0
Index 0, that’s where it says Wed
. What’s wrong with that? The problem is my computer runs Danish locale. If you want to parse a date-time string in English on computers of different locales, you need to specify an English-speaking locale, for example:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd hh:mm:ss zzz YYYY",
Locale.ENGLISH);
The same holds true if you are using SimpleDateFormat
. With this correction I get a different exception message:
Text 'Wed Jan 18 23:22:18 EST 2017' could not be parsed: Invalid value for ClockHourOfAmPm (valid values 1 - 12): 23
Isn’t this message wonderfully precise? The format had expected a value between 1 and 12 (inclusive) where you put 23. As menitoned in the comments, this is because you were using lowercase hh
where you intended uppercase HH
. After fixing this, we get
Text 'Wed Jan 18 23:22:18 EST 2017' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {DayOfMonth=18, DayOfWeek=3, MonthOfYear=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2017},ISO,America/New_York resolved to 23:22:18 of type java.time.format.Parsed
It’s more cryptic, but it does mention the problem that MadProgrammer also points out: the week-based year. This is what uppercase YYYY
gives you (and it’s a very common mistake, judging from the many questions on Stack Overflow with this exact problem). Let’s fix that too:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy",
Locale.ENGLISH);
Now we get the expected:
2017-01-18T23:22:18-05:00[America/New_York]
One final word of caution: the three and four letter time zone abbreviations like EST
come with some negative surprises too. DateTimeFormatter
understands EST
as UTC-5, which I suppose is what you want with a date in January (winter). For a date in the summer, would you still be expecting UTC-5, or would you expect EDT, that is, UTC-4? In your case you may be able to solve the ambiguity by supplying EDT
for Eastern Daylight Time, but generally it’s better to avoid those abbreviation and use the longer time zone IDs like America/New_York
and/or offsets like -05:00
.
The hour should be HH
, not hh
h Hour in am/pm (1-12)
And year should be yyyy
not YYYY
Y Week year
ALWAYS consult the JavaDocs first
String dateString = "Wed Jan 18 23:22:18 EST 2017";
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
try {
Date scheduleItemDate = sdf.parse(dateString);
System.out.println(dateString);
System.out.println(scheduleItemDate.toString());
System.out.println(sdf.format(scheduleItemDate));
} catch (ParseException e) {
System.out.println("Exception");
}
Which now prints...
Wed Jan 18 23:22:18 EST 2017
Wed Jan 18 23:22:18 EST 2017
Wed Jan 18 23:22:18 EST 2017