22

SimpleDateFormat is a very kind parser that rolls the resulting date instead of throwing an error. How can I parse a date strictly without regexps etc?

fmt = new SimpleDateFormat("dd.MM.yyyy")
fmt.parse("10.11.2012")   // it works
fmt.parse("10.1150.2012") // it works but it's unwanted
Pavel Vlasov
  • 4,206
  • 6
  • 41
  • 54
  • 3
    it may or may not solve your problem but, if you are dealing with dates in Java, I would strongly recommend the Joda Time library – Eduardo Oct 26 '12 at 13:47

3 Answers3

38

fmt.setLenient(false); is what you're looking for.

sp00m
  • 47,968
  • 31
  • 142
  • 252
  • 8
    Sadly setting lenient false is still lenient. "2010/01/5" is allowed for the pattern "yyyy/MM/dd". 20100901andGarbage" is allowed for the pattern "yyyyMMdd". I've posted an answer that guarantees strict matches using a class that extends SimpleDateFormat. – Steve Zobell Feb 05 '16 at 20:14
  • The doc of java.text.DateFormat.parse said "The method may not use the entire text of the given string. ", so the behavior is right. – Germinate Sep 14 '17 at 09:04
  • Someone may say it is not perfect solution, but I recommend this answer, that will cover most situations. – H.A.H. May 09 '22 at 14:12
14

java.time

You can also use the java.time package in Java 8 and later (Tutorial). Its parsing strictly checks the date values.

For example:

String strDate = "20091504";
TemporalAccessor ta = DateTimeFormatter.ofPattern("yyyyMMdd").parse(strDate);

Gives directly:

Exception in thread "main" java.time.format.DateTimeParseException:
Text '20091504' could not be parsed:
Invalid value for MonthOfYear (valid values 1 - 12): 15
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Ortomala Lokni
  • 56,620
  • 24
  • 188
  • 240
  • 2
    `DateTimeFormatter` has three resolver styles (compared to `DateFormat`’s two): strict, smart and lenient. Fortunately smart is the default, it will catch most unwanted input, and perhaps everything that is clearly incorrect. For still stricter validation you may of course try the strict resolver style. [The documentatio](http://docs.oracle.com/javase/8/docs/api/java/time/format/ResolverStyle.html) is rather informative. – Ole V.V. Jul 05 '17 at 06:35
  • 1
    `DateTimeFormatter` offers static methods which are cool. But it allows any day between 1 to 31. For example, it doesn't throw an exception for the 31st of February. ```DateTimeFormatter.ofPattern("yyyyMMdd").parse("20200231");``` – misbah Feb 27 '20 at 08:29
3

Unfortunately fmt.setLenient(false); will not achieve strict date formatting. It helps some, for example parsing "2010-09-01" using format "yyyyMMdd" will succeed if lenient==true, but the result is very bizarre: 2009/12/09.

Even if lenient==false parse() still acts lenient. "2010/01/5" is allowed for the pattern "yyyy/MM/dd". And data disagreement like "1999/2011" for the pattern "yyyy/yyyy" is tolerated (yielding 2011). Garbage is also allowed after the pattern match. For example: "20100901" and "20100901andGarbage" will both match "yyyyMMdd".

I have written an extension of SimpleDateFormat that enforces strict pattern matching. You can find it here:

SimpleDateFormat.parse() ignores the number of characters in pattern

In my version format() and parse() are functional inverses. This is what I think most people would expect.

Community
  • 1
  • 1
Steve Zobell
  • 896
  • 10
  • 13