Speed up your DateFormatter

Thorsten Stark
Dec 12, 2019 · 3 min read

Maybe you have heard of the slow performance of DateFormatter when it’s being initialized. But how slow is it really and what other calls may affect the performance of your app when working with date formats?

I came across that same question. So I decided to make a little experiment. Fortunately, Xcode has everything we need to measure that kind of metric. In your unit tests there is an option to measure the time of a code block:

self.measure {
// code block you want to measure
}

With this piece of code, it is fairly simple to run tests measuring the time for multiple kinds of operations. To get numbers that better compare I decided to run each target operation 10.000 times. The more samples you have the better the statistical results get.

One example test case looks like this:

func testPerformanceSetFormat() {
let dateFormatter = DateFormatter()
let dateString = "30.01.2020 19:35"
self.measure {
for _ in (0..<numberOfIterations) {
dateFormatter.dateFormat = "dd.MM.yyyy hh:mm"
let _ = dateFormatter.date(from: dateString)
}
}
}

In total I came up with 12 test cases:

  1. timeInterval: Date(timeIntervalSince1970: 597270773.0) as a reference how long it takes to initialize a Date with a TimeInterval. This approach uses no DateFormatter at all.
  2. dateFormatter (new): Create a new DateFormatter every time
  3. dateFormatter (reuse): Reuse one instance of a DateFormatter without any other changes. All other cases from here will reuse an instance of DateFormatter.
  4. dateFormat (set), calendar (set), timezone (set): Set the corresponding value every time to the same value.
  5. dateFormat (change), calendar (change), timezone (change): Changes the corresponding value to another value than before.
  6. calendar (once), timezone (once): Set the corresponding value only once before the measurement starts.
  7. cal + timezone (once): Set both values once before the measurement loop.

For the cases where a property is actually changed to another value than it had before, I changed the loop a little bit:

func testPerformanceAlternatingdTimezone() {
let dateFormatter = DateFormatter()
let dateString = "30.01.2020 19:35"
let timezone1 = TimeZone(secondsFromGMT: 0)
let timezone2 = TimeZone(secondsFromGMT: 5)
self.measure {
for _ in (0..<numberOfIterations/2) {
dateFormatter.timeZone = timezone1
let _ = dateFormatter.date(from: dateString)
dateFormatter.timeZone = timezone2
let _ = dateFormatter.date(from: dateString)
}
}
}

The number of iterations is cut to half because there are twice as many operations inside the loop.

Additional to the 10.000 iterations per test case, Xcode runs all tests with a measure block 10 times to calculate a mean value. This is necessary because it isn’t predictable how this single tasks will be scheduled inside the CPU, which results in varying run times. You can see this when you click on the grey diamond near the measure block. In the pop-up, you can see how the 10 runs took different lengths of time.

Image for post

I ran the complete test suite 3 times to be able to calculate my own mean values. So remember, the following numbers represent the seconds use for 10.000 operations for the given test case.

Image for post
Image for post

As expected, creating a Date from a TimeInterval is by far the fastest approach. But the surprise is that changing the calender property costs much more time than instantiating a new DateFormatter. And it is nearly 5 times slower than setting it once. Also changing the format seems to be a very expensive task. Whereas changing the timezone causes no significant difference compared to not changing it.

It also seems to be a good idea to set calendar and timezone at all instead of going with the default values of DateFormatter.

Conclusion

Based on these results when working with DateFormatter it seems to be most efficient to have reusable instances for differently configured formatters. This was a date formatter has to be configured only once and can be used again and again with only the minimum amount of computation time.

But if you have the chance to use timestamps instead of formatted date strings, you should use it.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store