0

I don't know why there is no error. The code is

String datestr = "2021-01-01";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
try {
    System.out.println(sdf.parse(datestr));
} catch (ParseException e) {
    e.printStackTrace();
}

Since the date string, 2021-01-01, does not match the format pattern string, yyyy-MM, I had expected and wanted an exception.

The console prints Fri Jan 01 00:00:00 CST 2021.

The opposite situation does result in an exception as expected. I make code look like this

        String datestr = "2021-01";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            System.out.println(sdf.parse(datestr));
        } catch (ParseException e) {
            e.printStackTrace();
        }

The console prints an error msg: Unparseable date: "2021-01"

Who can tell me why?

6
  • why you parse 2021-01 with yyyy-MM-dd, while parsing 2021-01-01 with yyyy-MM??? I'm really curious... Commented Apr 30, 2021 at 8:18
  • I recommend you don’t use SimpleDateFormat and Date. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use LocalDate and YearMonth, both from java.time, the modern Java date and time API. Commented Apr 30, 2021 at 18:02
  • 1
    Does this answer your question? SimpleDateFormat leniency leads to unexpected behavior Commented Apr 30, 2021 at 18:03
  • It’s an excellent question as it stands. There is no reason to close this question (said because it has received a couple of close votes). Commented Apr 30, 2021 at 18:07
  • Usage: SimpleDateFormat is not a function, it is a class. While in this case it was clear what you meant, in other cases using the right and agreed-upon terms will make the difference between people knowing exactly what you mean and people either not having a clue or worse, completely misunderstanding your intentions. Commented Apr 30, 2021 at 18:49

4 Answers 4

2

You are describing two different scenarios:

  1. Your input text contains more data than the pattern would consume and the extra data is at the end.
  2. Your input text contains less data than the pattern would consume.

#1 is not an error, since parse(String) is explicitly documented to just read from the beginning of the input until it has enough:

The method may not use the entire text of the given string.

#2 is an error, because you the pattern says it expects extra data (namely a - followed by a day) and that data is missing.

Sign up to request clarification or add additional context in comments.

Comments

2

tl;dr

Your formatting pattern must fit your input text. In the first case, "2021-01-01" does not match "yyyy-MM". In the second case, "2021-01" does not match "yyyy-MM-dd".

Use java.time classes instead, as wrestling with legacy classes SimpleDateFormat & Date is unwise. Simpler too, with no need of formatting patterns.

YearMonth
.from( 
    LocalDate.parse( "2021-01-01" ) 
)
.toString()

See this code run live at IdeOne.com.

2021-01

And parsing year-month:

YearMonth.parse( "2021-01" )

Details

You are using terrible date-time classes that were years ago supplanted by the modern java.time classes. Sun, Oracle, and the JCP community gave up on those closes with the unanimous adoption of JSR 310.

Your inputs happen to use standard ISO 8601 formats. The java.time classes use these formats by default when parsing/generating text. So no need to specify a formatting pattern.

LocalDate ld = LocalDate.parse( "2021-01-01" ) ;
YearMonth ym = YearMonth.from( ld ) ;
String output = ym.toString() ;

As for parsing an input of "2021-01":

YearMonth ym = YearMonth.parse( "2021-01" ) ;

1 Comment

@JoakimDanielson Fair enough, I revamped my Answer to be more on-point. Thank you for the critique.
1

Here’s a modest supplement. Basil Bourque has already shown the good and modern solution to the work you are doing, and Generous Badger has explained why your code didn’t behave the way you had expected.

The code by Basil Bourque does throw the expected exception if you feed a string in the wrong format into each of the code examples. For the modern version of the code you were asking about:

    String datestr = "2021-01-01";
    YearMonth.parse(datestr);

The result is an:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-01-01' could not be parsed, unparsed text found at index 7

Please also enjoy how precise the exception message is.

The same thing happens if you choose to use an explicit formatter:

    YearMonth.parse(datestr, DateTimeFormatter.ofPattern("uuuu-MM"));

Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-01-01' could not be parsed, unparsed text found at index 7

Don’t use SimpleDateFormat

There are a lot of confusing and ill-designed traits of SimpleDateFormat, the class that you tried to use in your two code examples. You have been hit by just of two of them:

  1. As Generous Badger explained, it may not parse the entire string given to it, tacitly leaving unparsed text.
  2. It invents default values for the fields not parsed. In your case it defaulted to the 1st of the month 00:00:00 in the default time zone of the JVM. While java.time can be instructed to apply default values for fields that are not in the parsed string, this requires specifying them explicitly in the Java code, leading to much more predictable and less surprising behaviour.

Comments

1

Others have already mentioned why this happens (the java parsers stop parsing when they get all they need) and have also explained that this API is older and not as ergonomic. That said, you can do what you want using the ParsePosition class.

String datestr = "2021-01-01";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
ParsePosition pp = new ParsePosition(0);
sdf.parse(datestr, pp);
if(pp.getIndex() < dateStr.length()) {
  throw new ParseException("Parsing failed...");
}

1 Comment

Thank you for your answer. It's a good idea.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.