Recently we discovered that we have been using java’s SimpleDateFormat in multiple global functions. This however is not the best idea since it turns out SimpleDateFormat is not threadsafe.

Let’s look at this simple example:

private val austrianTimeFormat = SimpleDateFormat("dd.MM.yyyy HH:mm:ss")
    .apply { timeZone = TimeZone.getTimeZone("Europe/Vienna") }

fun Date.toAustrianTime(): String {
  return austrianTimeFormat.format(this)
}

Since most of our users are from Austria, we use this function all the time. We thought that by creating one global SimpleDateFormat instance, we could lessen the load on the garbage collector a bit. So what’s the problem with that?

“SimpleDateFormat stores intermediate results in instance fields. So if one instance is used by two threads they can mess each other’s results. Looking at the source code reveals that there is a Calendar instance field, which is used by operations on DateFormat / SimpleDateFormat.”

The fix is simple:

private val austriaTimeZone: TimeZone = TimeZone.getTimeZone("Europe/Vienna")

fun Date.toAustrianTime(): String {
  return SimpleDateFormat("dd.MM.yyyy HH:mm:ss")
      .apply { timeZone = austriaTimeZone }
      .format(this)
}