12PM bug in Java
I’ve recently hit on a nasty bug in Java. It sits in Date
class and shows up only at noon!
I’m going to demonstrate it using Groovy shell, but you can reproduce it in plain Java environment too.
format = new java.text.SimpleDateFormat('EEE MMM d hh:mm:ss z yyyy')
//= java.text.SimpleDateFormat@fbb27a1c
originalDate = 'Sun Jul 28 13:14:15 EDT 2013'
//= Sun Jul 28 13:14:15 EDT 2013
date = format.parse(originalDate)
//= Sun Jul 28 13:14:15 EDT 2013
parsedDate = date.toString()
//= Sun Jul 28 13:14:15 EDT 2013
assert originalDate == parsedDate
//= null
So far so good.
I chose a specific formatter on line 1 to make the bug even more evident. With this formatter lines 5, 8, and 11 must be identical on my machine, and they are in this example. The assertion on line 13 also proves the equality.
Now let’s change the example date to one hour earlier
originalDate = 'Sun Jul 28 12:14:15 EDT 2013'
//= Sun Jul 28 12:14:15 EDT 2013
date = format.parse(originalDate)
//= Sun Jul 28 00:14:15 EDT 2013
parsedDate = date.toString()
//= Sun Jul 28 00:14:15 EDT 2013
Lines 2, 5, and 8 are not identical any more. The String representation of the date is 12 hours off.
To make sure the problem is in toString
and not in parse
, let’s format the date using formatter
format.format(date)
//= Sun Jul 28 12:14:15 EDT 2013
Looks good. The problem is in toString
indeed. Or is it?
Let’s parse 13 o’clock date and 12 o’clock date. The difference between them should be 1 hour. In reality
date13 = 'Sun Jul 28 13:14:15 EDT 2013'
//= Sun Jul 28 13:14:15 EDT 2013
date12 = 'Sun Jul 28 12:14:15 EDT 2013'
//= Sun Jul 28 12:14:15 EDT 2013
(format.parse(date13).time - format.parse(date12).time) / (1000 * 60 * 60)
//= 13
Wow, the problem is actually in parse
. Then how come the format
returned the correct value? That’s still a mystery to me.
I’m actually quite surprised that this bug survived through JDK 1.7.0_09, and neither Sun nor Oracle hasn’t fixed it yet.