dateFormat’s One Big Mistake

Your location. Your timeZone.

Image for post
Image for post
Photo by freestocks on Unsplash

This article will cover the big issue with dateFormatter, and how you might overcome it. Be aware that I’ve coded everything within this article in Swift using Playgrounds.

No Problem: Creating a Date

let now: Date = Date()

No obvious problem: Displaying a date

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-mm-dd"
let dateString = dateFormatter.string(from: now)
print (dateString)

Now since today is Sunday 3rd May 2020, on my machine I print to the console:

2020-56-03

Have you seen the problem in what I’ve written above?

The problem

dateFormatter is not locale aware, and this means that the user can potentially change this (like their region) from their device.

Solution number one:

Force the locale to be the region you want (for example, if you wear a cowboy hat the US).

let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US")
dateFormatter.dateFormat = "yyyy-mm-dd"
dateFormatter.timeZone = TimeZone(identifier: "Europe/London")
let dateString = dateFormatter.string(from: now)
print (dateString)

the output of this would be:

2020-12-03

which does sound nice, but then we are enforcing this format on the whole world. If you have an Internationally released App this is certainly not recommended.

Solution number two:

Force the user to view ISO8601DateFormatter. This means (probably) a physical fight with your designer, one which you will lose (sorry). If you want to handle fractional seconds you will need dateFormatter.formatOptions.insert(.withFractionalSeconds).

let dateFormatter = ISO8601DateFormatter()
dateFormatter.timeZone = TimeZone(identifier: "Europe/London")
dateFormatter.formatOptions = [.withMonth, .withDay, .withTime, .withDashSeparatorInDate, .withColonSeparatorInTime]
let dateString = dateFormatter.string(from: now)
print (dateString)

Solution number three:

Leverage Apple’s documentation on the matter, and prefer dateStyle/timeStyle. This avoids the painful hard-coded formats that are bug-prone and…not the way to approach things. This then uses the user’s device settings for Locale and timeZone.

let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .full
let dateString = dateFormatter.string(from: now)
print (dateString)

Solution number Four:

Using a custom date format, the best way is to avoid hard-coded strings and instead use func dateFormatter.setLocalizedDateFormatFromTemplate(_ dateFormatTemplate: String)

let dateFormatter = DateFormatter()
dateFormatter.setLocalizedDateFormatFromTemplate("yyyyMMMMddhhmm")
let dateString = dateFormatter.string(from: now)
print (dateString)

Conclusion

You need to be aware that some dates can fail for some regions. This problem is so common that Apple have produced documentation for this — so be aware!

You need to be aware that software you create needs to be flexible for any users of your software — even if your software is only available in one store users can change their locales, regions and user settings. Be aware that you can’t control a user’s device and it is wise to make your software work well on any possible settings on the host devices.

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