3

I recently realized/learned that SimpleDateFormat has some serious issues and since Java 8 should not be used anymore. I mean... I kind of knew it but never payed much attention to that. So far so good.

But then OK... I have lots of legacy code written in the last 7-8 years which does use SimpleDateFormat, stores many SimpleDateFormat objects as static fields, and uses them to parse/format dates. And actually I've never had any issues with these SimpleDateFormat instances (static or not) in production (for all these years).

So... I want to now review and analyze this legacy code and see if there are really any dangerous uses of SimpleDateFormat in it.

Therefore my question is...

Under what scenarios exactly is SimpleDateFormat problematic to use?
Can I get some sort of checklist so that I review my old code and see if any of my scenarios are in that "try to avoid" list?

Nathan Hughes
  • 85,411
  • 19
  • 161
  • 250
peter.petrov
  • 34,474
  • 11
  • 63
  • 118
  • 1
    It is not thread safe, So if two threads use the same `SimpleDateFormat` object at the same time you get a problem. – Henry Apr 22 '16 at 13:25
  • @Henry Yes, I've heard so... But OK... is that the only problem with it? – peter.petrov Apr 22 '16 at 13:26
  • 1
    If the code is currently working, there aren't suddenly new defects added. However, the new Date & Time API is **much** easier to use correctly. – Elliott Frisch Apr 22 '16 at 13:26
  • What are the 'serious issues' you learned about? It is perhaps an unnecessary hassle that SimpleDateFormat instances are not thread safe, but thread safety is not just an issue with the formatters in the Java API, but something you have to consider everywhere. – jarnbjo Apr 22 '16 at 13:27
  • 2
    @jarnbjo Mostly these described here: http://stackoverflow.com/questions/6840803/simpledateformat-thread-safety Hm... so ... is it really an unnecessary hassle or not? – peter.petrov Apr 22 '16 at 13:29
  • 1
    @peter.petrov The question you are linking to discusses the lack of thread safety in the SimpleDateFormat class. Is that what you call a 'serious issue' and a reason to avoid the class? If so, large parts of the standard Java API (collections, disk and networking I/O, AWT/Swing) has 'serious issues' and must be avoided. – jarnbjo Apr 22 '16 at 13:41
  • @jarnbjo Come on... I am just trying to get a better idea what exactly is wrong with this class and what scenarios should be avoided. If you don't like the word "serious" I can remove it. – peter.petrov Apr 22 '16 at 13:42
  • @peter.petrov And I am trying to understand what 'some (multiple!) serious issues' you have heard about. If all you are concerned about is thread safety (serious or not), then this question is a duplicate of the question you are linking to. – jarnbjo Apr 22 '16 at 13:46
  • 1
    When analyzing the legacy code you can at least sort out all locally created instances of `SimpleDateFormat` within method bodies (thread-safe). You only need to investigate shared instances in order to evalute if its usage is safe or not (ie. are there multiple threads in given context accessing the same instance). – Meno Hochschild Apr 22 '16 at 13:46
  • @peter.petrov SimpleDateFormat has mutable fields which can get corrupted if more than one thread uses it at once, which is perhaps the most common reason an object isn't thread safe. – Peter Lawrey Apr 22 '16 at 13:49
  • Re, "I am just trying to get a better idea [of] what scenarios should be avoided": According to the javadoc for `SimpleDateFormat`, you should avoid using any instance of the class in more than one thread. – Solomon Slow Apr 22 '16 at 15:26

3 Answers3

3

SimpleDateFormat is not threadsafe, any scenario where you put it in a field accessed by multiple threads is going to be a potential problem. It won't blow up on you, but it can cause incorrect results to be generated.

Triaging cases of this would be a matter of checking what you're using the results for and how important it is that those values are always correct. Also obviously the more threads you have hitting a formatter the greater the chance of errors, so applications that are multithreaded but which rarely have more than one user might be prioritized downward.

Nathan Hughes
  • 85,411
  • 19
  • 161
  • 250
2

One problem, for example, is that SimpleDateFormat has an internal field that is set to the date/calendar you want to format.

So if you have two threads using the same SDF concurrently with two different dates, the date being formatted may change right in the middle of the formatting, resulting in a String that is a mix between the two dates.

That is what the example below simulates. If you run it with ExecutorService es = Executors.newFixedThreadPool(1); (single threaded), the resulting set only has two dates, as expected. If you use ExecutorService es = Executors.newFixedThreadPool(10); instead (multi threaded), it is likely that the resulting set will have more dates, which are a mix of the two dates.

For example, on my machine the outputs are:

  • single threaded (expected result):

    [02-Jan-1970 04:46:40, 01-Jan-1970 01:00:00]

  • multi threaded:

    [02-Jan-1970 01:00:00, 01-Jan-1970 04:00:00, 02-Jan-1970 01:00:40, 01-Jan-1970 01:00:40, 02-Jan-1970 04:46:00, 02-Jan-1970 01:46:00, 01-Jan-1970 01:00:00, 02-Jan-1970 04:00:00, 02-Jan-1970 01:46:40, 02-Jan-1970 04:00:40, 01-Jan-1970 01:46:00, 01-Jan-1970 01:46:40, 02-Jan-1970 04:46:40, 01-Jan-1970 04:00:40, 01-Jan-1970 04:46:40, 01-Jan-1970 04:46:00]


private static final DateFormat FMT = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
private static final CountDownLatch LATCH = new CountDownLatch(1);

public static void main(String[] args) throws Exception {
  ExecutorService es = Executors.newFixedThreadPool(1);
  Date d1 = new Date(0);
  Date d2 = new Date(100_000_000);
  List<Future<String>> futures = new ArrayList<> ();
  for (int i = 0; i < 10_000; i++) {
    Date d = i % 2 == 0 ? d1 : d2;
    Future<String> f = es.submit(() -> run(d));
    futures.add(f);
  }
  LATCH.countDown();
  es.shutdown();
  es.awaitTermination(5, TimeUnit.SECONDS);
  Set<String> results = new HashSet<> ();
  for (Future<String> f : futures) {
    results.add(f.get());
  }

  System.out.println(results);
}

private static String run(Date d) throws InterruptedException {
  LATCH.await();
  return FMT.format(d);
}
Community
  • 1
  • 1
assylias
  • 297,541
  • 71
  • 621
  • 741
1

SimpleDateFormat is not thread safe so in each multithread scenario (a web application for example) you cannot declare one formatter in a constants class and use it all around your business methods without the risk of strange bugs... expecially when you start to play with timezones and such.

Matteo Baldi
  • 4,684
  • 9
  • 33
  • 44