I have date in string format and I want to parse that into util date.
var date =\"03/11/2013\"
I am parsing this as :
new S
Jon Skeet’s answer is correct and was a good answer when it was written in 2013.
However, the classes you use in your question, SimpleDateFormat
and Date
, are now long outdated, so if someone got a similar issue with them today, IMHO the best answer would be to change to using the modern Java date & time API.
I am sorry I cannot write Scala code, so you will have to live with Java. I am using
private static DateTimeFormatter parseFormatter
= DateTimeFormatter.ofPattern("MM/dd/yyyy");
The format pattern letters are the same as in your question, though the meaning is slightly different. DateTimeFormatter
takes the number of pattern letters literally, as we shall see. Now we try:
System.out.println(LocalDate.parse(date, parseFormatter));
Results:
"03/11/2013"
is parsed into 2013-03-11
as expected. I used the modern LocalDate
class, a class that represents a date without time-of-day, exactly what we need here."03/88/2013 hjhkjhk"
gives a DateTimeParseException
with the message Text '03/88/2013 hjhkjhk' could not be parsed, unparsed text found at index 10
. Pretty precise, isn’t it? The modern API has methods to parse only part of a string if that is what we want, though."03/88/201309"
gives Text '03/88/201309' could not be parsed at index 6
. We asked for a 4 digit year and gave it 6 digits, which leads to the objection. Apparently it detects and reports this error before trying to interpret 88 as a day of month."03/88/2013"
gives Text '03/88/2013' could not be parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 88
. Again, please enjoy how informative the message is."03-08-2013"
(with hyphens instead of slashes) gives Text '03-08-2013' could not be parsed at index 2
, not very surprising. Index 2 is where the first hyphen is.Jon Skeet explained that the outdated SimpleDateFormat
can be lenient or non-lenient. This is true for DateTimeFormatter
too, in fact it has 3 instead of 2 resolver styles, called ‘lenient’, ‘smart’ and ‘strict’. Since many programmers are not aware of this, though, I think they made a good choice of not making ‘lenient’ the default (‘smart’ is).
What if we wanted to make our formatter lenient?
private static DateTimeFormatter parseFormatter
= DateTimeFormatter.ofPattern("MM/dd/yyyy")
.withResolverStyle(ResolverStyle.LENIENT);
Now it also parses "03/88/2013"
, into 2013-05-27
. I believe this is what the old class would also have done: counting 88 days from the beginning of March gives May 27. The other error messages are still the same. In other words it still objects to unparsed text, to a 6 digit year and to hyphens.
Question: Can I use the modern API with my Java version?
If using at least Java 6, you can.
You should use DateFormat.setLenient(false)
:
SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
df.setLenient(false);
df.parse("03/88/2013"); // Throws an exception
I'm not sure that will catch everything you want - I seem to remember that even with setLenient(false)
it's more lenient than you might expect - but it should catch invalid month numbers for example.
I don't think it will catch trailing text, e.g. "03/01/2013 sjsjsj". You could potentially use the overload of parse
which accepts a ParsePosition
, then check the current parse index after parsing has completed:
ParsePosition position = new ParsePosition(0);
Date date = dateFormat.parse(text, position);
if (position.getIndex() != text.length()) {
// Throw an exception or whatever else you want to do
}
You should also look at the Joda Time API which may well allow for a stricter interpretation - and is a generally cleaner date/time API anyway.