Formatting dates in Swift using Date.FormatStyle on iOS 15Published on: May 27, 2022
Formatting dates in Swift using Date.FormatStyle on iOS 15
Working with dates isn’t easy. And showing them to your users in the correct locale hasn’t always been easy either. With iOS 15, Apple introduced a new way to convert
Date objects from and to
String. This new way comes in the form of the new
Formatter api that replaces
As any seasoned iOS developer will tell you,
DateFormatter objects are expensive to create, and therefor kind of tedious to manage correctly. With the new
Formatter api, we no longer need to work with
DateFormatter. Instead, we can ask a date to format itself based on our requirements in a more performant, easier to use way.
In this post I will show you how you can convert
Date objects to
String as well as how you can extract a
Date from a
Converting a Date to a String
The most straightforward way to convert a
Date to a
String is the following:
let formatted = Date().formatted() // 5/26/2022, 7:52 PM
By default, the
formatted() function uses a compact configuration for our
String. The way
formatted() converts our
String takes into account the user’s current locale. For example, if my device was set to be in Dutch, the date would be formatted as
26-5-2022 19:54 which is a more appropriate formatting for the Dutch language.
However, this might not always be what we need. For example, we might want to have our date formatted as
May 26 2022, 7:52 PM. We can use the following code to do that:
let formatted = Date().formatted( .dateTime .day().month(.wide).year() .hour().minute() )
Let’s break this code apart a bit. The
formatted function takes an object that conforms to the
FormatStyle protocol as its argument. There are various ways for us to create such an object. The
FormatStyle protocol has several convenient extensions that can provide us with several different formatters.
For example, when sending a
Date to a server, we’ll often need to send our dates as ISO8601 compliant strings. Before I explain the code you just saw, I want to show you how to grab an ISO8601 compliant string from the current
let formatted = Date().formatted(.iso8601) // 2022-05-26T18:06:55Z
Okay, back to the example from before. The
.datetime formatter is used as a basis for our custom formatting. We can call various functions on the object that’s returned by the
.datetime static property to select the information that we want to show.
Some of these properties, like the month, can be configured to specify how they should be formatted. In the case of
.month, we can choose the
.wide formatting to spell out the full month name. We could use
.narrow to abbreviate the month down to a single letter, or we could use one of the other options to represent the month in different ways.
If you omit a property, like for example
.year(), our formatted date will omit the year that’s embedded in the
Date. And again, the underlying formatter will always automatically respect your user’s locale which is really convenient.
Another way to format the date is to by specifying how you want the date and time to be formatted respectively:
let formatted = Date().formatted(date: .complete, time: .standard) // Thursday, May 26, 2022, 8:15:28 PM
The above provides a very verbose formatted string. We can make a more compact one using the following settings:
let formatted = Date().formatted(date: .abbreviated, time: .shortened) // May 26, 2022, 8:16 PM
It’s even possible to omit the date or time entirely by using the
let formatted = Date().formatted(date: .abbreviated, time: .omitted) // May 26, 2022
There are tons of different combinations you could come up with so I highly recommend you explore this api some more to get a sense of how flexible it really is.
Creating a Date from a String
Date is slightly less convenient than going from a
Date to a
String but it’s still not too bad. Here’s how you could cover the common case of converting an ISO8601 compliant string to a
let string = "2022-05-26T18:06:55Z" let expectedFormat = Date.ISO8601FormatStyle() let date = try! Date(string, strategy: expectedFormat)
We make use of the
Date initializer that takes a string and a formatting strategy that’s used to parse the string.
We can also use and configure an instance of
FormatStyle to specify the components that we expect to be present in our date string and let the system parse it using the user’s locale:
let string = "May 26, 2022, 8:30 PM" let expectedFormat = Date.FormatStyle() .month().year().day() .hour().minute() let date = try! Date(string, strategy: expectedFormat)
The order of our date components doesn’t matter; they will automatically be rearranged to match the user’s locale. This is super powerful, but it does mean that we can’t use this to parse dates on devices that use a different locale than the one that matches the string’s locale. The best locale agnostic date string is ISO8601 so if you have control over the date strings that you’ll parse, make sure you use ISO8601 when possible.
In this short article, you learned how you can use iOS 15’s
FormatStyle to work format
Date objects. You saw how to go from
String, and the other way around. While
FormatStyle is more convenient than
DateFormatter, it’s iOS 15 only. So if you’re still supporting iOS 14 you’ll want to make sure to check out