Java SimpleDateFormat gives wrong results
October 24, 2012 4 Comments
Would you expect the following lines of code to ever print something to the standard output?
public static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); ... Date date = dateFormat.parse("2012-10-26"); String reformat = dateFormat.format(date); if (!"2012-10-26".equals(reformat)) { System.out.println("Wrong date: " + reformat); }
Indeed, there are situations when such code will occasionally fail.
The SimpleDateFormat class is not thread safe, that means whenever two or more separate threads access the same class instance, the results from the parse() and format() methods can produce wrong results.
To reproduce this effect, I show the full test code:
package com.udojava.blog; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class DateFormatDemo { public static SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd"); public class DemoThread extends Thread { @Override public void run() { for (int i = 0; i < 100; i++) { try { Date date = dateFormat.parse("2012-10-26"); String reformat = dateFormat.format(date); if (!"2012-10-26".equals(reformat)) { System.out.println("Wrong date: " + reformat); } } catch (ParseException e) { e.printStackTrace(); } } } } public void testRun() { DemoThread t1 = new DemoThread(); DemoThread t2 = new DemoThread(); t1.start(); t2.start(); } public static void main(String[] args) { new DateFormatDemo().testRun(); } }
If you run this, you will get differing outputs from one run to the next run, something like this:
Wrong date: 2201-10-26
Wrong date: 2201-10-26
Wrong date: 2012-12-26
Exception in thread "Thread-1" java.lang.NumberFormatException: empty String
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1011)
at java.lang.Double.parseDouble(Double.java:540)
at java.text.DigitList.getDouble(DigitList.java:168)
at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2088)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
at java.text.DateFormat.parse(DateFormat.java:355)
at com.udojava.blog.DateFormatDemo$DemoThread.run(DateFormatDemo.java:18)
So, sometimes it can be dangerous to try to over-optimize by using static members that are shared between threads. Even simple things like a SimpleDateFormat can fail in multithreading.
And they usually then fail only in 1 out of 1000 times, making it a real horror to find, debug and fix those issues.
Pingback: The Unparseable Date Pitfall « Udo's Java Blog
“And they usually then fail only in 1 out of 1000 times, making it a real horror to find, debug and fix those issues.”
So true!
Thank you!! Saved a lot of time for me…
Thank you very much!