2

I'm confused why the following input data is not parsed correctly by SimpleDateFormat.

I was trying to test various possible allowed date formats on a String to see if it would parse correctly with one of the formats.

Note: Other incorrect date formats that I've used report a parsing error. That's what I expect to see.

What am I doing wrong? Or, what can I do as a workaround?

String dformat = "MM-dd-yyyy";
String cDate = "2013-12-28";
SimpleDateFormat f = new SimpleDateFormat(dformat);
Date dd = f.parse(cDate); 

The result is success. And the date that is parsed is:

Date Fri Sep 12 00:00:00 PST 195

Well, the date should be December 28th, 2013. In this case, I expected to see (like what I see for other invalid formats):

java.text.ParseException: Unparseable date: "2013-12-28"
qps
  • 43
  • 4
George Hernando
  • 2,550
  • 7
  • 41
  • 61

6 Answers6

2

You should really consider using the new java 8 version of java.util.Date which is java.time.LocalDate and java.time.LocalDateTime as part of the SDK. These Date API's are considered more stable for exactly the reason you are having issues. Here is one example.

String armisticeDate = "2013-12-28";

LocalDate aLD = LocalDate.parse(armisticeDate);
System.out.println("Date: " + aLD);

String armisticeDateTime = "2013-12-28T11:50";

LocalDateTime aLDT = LocalDateTime.parse(armisticeDateTime);
System.out.println("Date/Time: " + aLDT);

If you want to create a different format you can do the below.

String anotherDate = "04 Apr 2016";

DateTimeFormatter df = DateTimeFormatter.ofPattern("dd MMM yyyy");
LocalDate random = LocalDate.parse(anotherDate, df);

System.out.println(anotherDate + " parses as " + random);

For full documentation check out the Oracle page.

https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html

Scott
  • 174
  • 1
  • 13
2

To get the error message:

java.text.ParseException: Unparseable date: "2013-12-28"

you need to call:

f.setLenient(false);

As the javadoc of parse(String source, ParsePosition pos) says:

By default, parsing is lenient: If the input is not in the form used by this object's format method but can still be parsed as a date, then the parse succeeds. Clients may insist on strict adherence to the format by calling setLenient(false).

Andreas
  • 154,647
  • 11
  • 152
  • 247
1

You code should be like that:

  String dformat = "yyyy-MM-dd";
  String cDate = "2013-12-28";
  SimpleDateFormat f = new SimpleDateFormat(dformat);
  Date dd = f.parse(cDate);

The date format is wrong in your question.

Thiago Procaci
  • 1,485
  • 11
  • 16
  • Yes, that will parse it correctly. But the date format is unknown initially and I would like to test various formats to find the correct one. Parsing here was successful (although the date was wrong). I wanted it to report an error. – George Hernando Mar 28 '18 at 17:20
  • First, you probably need to investigate all possible date formats you might find in your application. By analyzing it, construct an algorithm to discover the correct format. Hard task, not impossible though. – Thiago Procaci Mar 28 '18 at 17:49
1

Well the dformat do not meet the cDate format. So you have to give either cDate in dformat or you have to change the dformat in ""yyyy-MM-dd"

Florin Lei
  • 521
  • 8
  • 16
  • All answers so far say to change the date format to match the string, but I am trying the find the correct date format for a string whose format I don't know. I want the parse function to report an error, but instead it "successfully" parses the string. – George Hernando Mar 28 '18 at 17:26
1

Your format pattern and date string does not much. Change to:

String dformat = "yyyy-MM-dd";
AlexGera
  • 756
  • 9
  • 19
  • All answers so far say to change the date format to match the string, but I am trying the find the correct date format for a string whose format I don't know. I want the parse function to report an error, but instead it "successfully" parses the string. – George Hernando Mar 28 '18 at 17:26
  • If you dig into source code, by default it formats your date with don't care position to date string. And parse it accordingly. So you simply set a weird string for it. If you want to generate format dynamically you would need to preparse the strings by your self – AlexGera Mar 28 '18 at 17:30
1

Well, SimpleDateFormat is known to be a problematic and bugged class, with lots of strange behaviours.

What's probably happening is something similar to the issue described in this article. Considering your pattern and the input:

MM-dd-yyyy
2013-12-28

It's probably reading the month as "20", day as "3" and year as "-28"? (or some other value because I'm not sure how it interprets 2-28 as a 4-digit number). And the final result of this mess is a completely wrong, bizarre date - and don't ask me how it gets to the final result, it's a mistery to me.

Anyway, that can happen when the pattern doesn't match the input format, and the actual values that SimpleDateFormat reads will be something not so predictable and somewhat counter-intuitive. But what really matters is the fact that this class has lots of issues and design flaws, and it's lenient by default, so it tries to be "smart" and does lots of strange things before giving an error.

If you want to validate the input, just turn off the lenient mode, by calling f.setLenient(false) as Andreas suggested. This will throw an exception when the input doesn't match the pattern.

But if you're using Java 8, then you should use the java.time API, which is far superior and it solves lots of problems that SimpleDateFormat has.

To check if a string contains a date in a specific format, use a java.time.format.DateTimeFormatter. This class is not lenient by default as SimpleDateFormat, so it should work as expected:

// use the format "month-day-year"
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("MM-dd-yyyy");
// try to parse a string in a different format (year-month-day)
LocalDate dt = LocalDate.parse("2013-12-28", fmt); // exception

The code above tries to create a LocalDate, a class that represents a date (only day, month and year). But if you want to just validate the input (without assigning it to any variable), you can just use the formatter:

fmt.parse("2013-12-28"); // exception
qps
  • 43
  • 4