« iCab 4.0.0 and iCab 3.0.5 Public Releases | Main | iCab 4.0.1 »

Thu, Jan 17, 2008

Parsing 2-Digit Years with Java's SimpleDateFormat

If you have to format and parse date strings like "17.01.2008" (in this case, the German date format) with Java, you'd probably use a java.text.SimpleDateFormat:

SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
Date now = new Date();
System.out.println( sdf.format(now) );  // something like "17.01.2008"
Date then = sdf.parse( "17.01.1908" );
System.out.println( sdf.format(then) );  // "17.01.1908"

This works as expected. But now some fancy user dares to input the year with only two digits:

SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
Date fancy = sdf.parse( "17.01.08" );
System.out.println( sdf.format(fancy) );  // "17.01.0008" - oops!

This is a feature that one easily fails to see in the API: If the year pattern is not "y" or "yy", year numbers are parsed literally and not relatively to some century. Using the short pattern works fine for parsing, but you'll need a second pattern for output:

SimpleDateFormat input  = new SimpleDateFormat("dd.MM.yy");
SimpleDateFormat output = new SimpleDateFormat("dd.MM.yyyy");
Date ok1 = input.parse( "17.01.08" );
Date ok2 = input.parse( "17.01.2008" );
System.out.println( output.format(ok1) );  // "17.01.2008"
System.out.println( output.format(ok2) );  // "17.01.2008"

You can read (and set) the century offset using the property 2DigitYearStart.

And while we're at it: If you want to prevent SimpleDateFormat from parsing an illegal date like "32.01.2008", you'll have to switch off the lenient mode:

SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yy");
sdf.setLenient( false );
Date illegal = sdf.parse( "32.01.1908" );  // ParseException
Posted by Thomas Much at 18:05
Categories: Java