Compare performance of Java’s SimpleDateFormat against DateTimeFormatter

Martin Grigorov
3 min readJun 11, 2020

--

java.text.SimpleDateFormat is a well known utility used by Java developers for formatting and parsing dates. It is available since the early versions of Java, most probably since version 1.0.

Its API is simple and intuitive

SimpleDateFormat formatter = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");String formatted = formatter.format(new java.util.Date());Date date = formatter.parse("Wed, 4 Jul 2001 12:08:56 -0700");

but it has drawbacks. Here are few of them:

  • it is not thread-safe, i.e. an instance cannot be used concurrently by several Java threads. Its javadoc says: “It is recommended to create separate format instances for each thread.”
  • SimpleDateFormat can change its configured time zone if it is asked to parse a date with a different time zone [bug report]
  • creating new instances is not cheap. Its constructor compiles the passed date-time pattern and if you create a new instance of SimpleDateFormat for each usage then it usually appears in CPU profiling results.

Java 8 introduced new API for date, time, instants and durations that is recommended to use instead of the old APIs based around java.util.Date and java.util.Calendar classes.

A new member of the new APIs is java.time.format.DateTimeFormatter that is the closest replacement of java.text.SimpleTextFormat. I say “closest” because the patterns it supports are not exactly the same. The good thing about the new date time APIs is that the classes are immutable and thus thread-safe, i.e. a single instance of DateTimeFormatter can be shared and used by more than one threads!

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE, d MMM yyyy HH:mm:ss Z", Locale.US);String formatted = formatter.format(java.time.LocalDateTime.now());java.time.temporal.TemporalAccessor ta = formatter.parse(“Wed, 4 Jul 2001 12:08:56 -0700”);java.time.LocalDateTime dateTime = java.time.LocalDateTime.from(ta);

Apache Tomcat is the most popular Java web server. It is developed long before Java 8 has been released. Actually it started using Java 8 with version 9.0.0 which the the latest stable branch at the moment (9.0.36).

As you may know HTTP request and response headers may contain dates, e.g. If-Modified-Since and Last-Modified. So parsing and formatting dates is a crucial part of processing requests and serving responses. As any other web server Apache Tomcat is trying to do this task in the fastest way possible.

The date parsing/formatting code is from the pre-Java 8 times, so it is based around SimpleDateFormat class. But to overcome the drawbacks above it uses a pool of SimpleDateFormat instances which are being reused across the http processing threads. Whenever a thread needs to format a date then a formatter is removed temporarily from the pool, used and finally returned to the pool. If there is no available formatter then a new instance is created, used and added to the pool. This way any given instance is used by at most one thread and they are instantiated once and reused, so there is no wasted time in re-compiling the patterns.

The implementation of date related classes can been seen here and here.

Let’s check whether this pool based solution could be simplified by using Java 8 java.time.format.DateTimeFormatter!

Here is the implementation of FastHttpDateFormat based on DateTimeFormatter: DateTimeBasedFormat.java. It provides the same method signatures as Tomcat’s FastHttpDateFormat so they can easily be swapped. Here is a simple unit test that proves they do the same thing: DateTimeBasedFormatTest.java.

Tomcat already has a performance test for FastHttpDateFormat that prints the amount of nanoseconds it take to execute 800 million calls (8 threads x 100M calls) to FastHttpDateFormat.getCurrentDate(). For this comparison I have used JMH (Java Microbenchmark Harness) because it is specially designed for making micro benchmarks and provides more detailed results: HttpDateFormatBenchmark.java

The throughput outcome of the test is:

HttpDateFormatBenchmark.datetime thrpt 5 37350299.511 ± 17415309.455 ops/s
HttpDateFormatBenchmark.tomcat thrpt 5 170712511.688 ± 53146373.080 ops/s

So, it seems Tomcat’s solution is around 5 times faster than Java 8 DateTimeFormatter!

Being thread-safe and immutable makes Java 8 DateTime APIs easier and predictable to use but for the price of being slower than the “problematic” (when used without care!) SimpleDateFormat.

Most of the business applications most probably do not need such kind of extreme performance so better use Java 8 DateTime APIs! But if your CPU profiler tells you that this is a bottleneck for your application then you may take inspiration from Tomcat’s FastHttpDateFormat and ConcurrentDateFormat classes!

--

--

Responses (1)