SimpleDateFormat possible error in method parse

2019-02-25 06:25发布

问题:

I receive a string that represent a date, I need convert this string to date, and validate that the string is a valid date.

I receive the string 33-12-2013 a the parse method return a date 01-01-2014, the code:

Date fechaVencimientoFormateada;
SimpleDateFormat formateador = new SimpleDateFormat( "dd-MM-yyyy" );
try
{
    fechaVencimientoFormateada = formateador.parse( "33-12-2013" );      
    System.out.println( formateador.format(fechaVencimientoFormateada) );
}
catch ( ParseException e )
{
    System.out.println("ERROR!");
}

the output: Thu Jan 02 00:00:00 COT 2014

and I expected a ParseException, any idea?

And other examples:

String date: 365-12-2013 output: Sun Nov 30 00:00:00 COT 2014

String date: 1-24-2013 output: Mon Dec 01 00:00:00 COT 2014

why ParseException is not throwing?

回答1:

Make sure you setLenient(false) on the SimpleDateFormat. Otherwise it will parse lots of invalid dates without exception and you can't trust the output too much.



回答2:

The parser will try to parse your input as best as he can unless you define its lenient flag to false, in which case the parser will be strict with the pattern you provided. By default (in your case) this flag is set to true, meaning that any incoherence in the input will try to be salvaged, resulting in an unexpected output if you don't know quite well how does it work.

With "as best as he can" I meant this:

With lenient parsing, the parser may use heuristics to interpret inputs that do not precisely match this object's format.

Let's take a look at your examples:

String date: 365-12-2013 output: Sun Nov 30 00:00:00 COT 2014

The exceeding gap between the maximum allowed number of day, month or year, will be added in the specific unit it is exceeding. In this case, you can go up to December 31, because the field that's "overflowing" is the day. You'll have 31 days to set and 334 left to go, which will be still added as days.

Long story short: 334 days after December 31, 2013 comes November 30, 2014.

String date: 1-24-2013 output: Mon Dec 01 00:00:00 COT 2014

In this case, the principle is the same but it is applied to months. In this case, the maximum month possible is 12, so, with 12 more months left to go, you're actually adding a year to your date. resulting in the output you received.

Setting the lenient flag to false will enforce strict adherence to the pattern and the exceptions you seek will be properly thrown.



回答3:

The SimpleDateFormat class implements the Robustness Principle:

Be conservative in what you do, be liberal in what you accept from others

The implementors were probably aware of the behaviour of most Unix implementations of the POSIX mktime, which has similar behaviour.

Whether that is wise is arguable.