New Date Formatter API in Swift
Master the new formatter API with a bunch of helpful examples
From Swift 5.5 and iOS 15 onwards, we have a new formatter API that allows us to display String Dates in a more declarative and intuitive way. Before we dive into it, let’s recap on how the actual formatter API works with the following example.
This is fairly enough. We use the static factory pattern to create a reusable DateFormatter and then, we create a utility function to parse a Date to a String, given a specific formatter.
The problem with this approach is that if we want to display a date in a different format, we’ll need to create another DateFormatter. And besides that, we are not taking into account the user’s language settings by “hard coding” the formats. For example in Spanish, the Dates format follows the dd/MM/yy pattern instead of MM/dd/yy.
The new formatter API resolve this problem giving us the possibility to describe the way we want to display our Dates instead of configuring a DateFormatter. We now have four format functions available for use:
Let’s start with the most basic example, using option one. This will transform our Date to a default String format (Date + Time).
We can’t make any transformation but there are cases that this format is enough for us. If we want to customize our date format, we’ll need to use option number two.
It’s a little tricky at the beginning but it gets easier once you understand how to actually use it.
We need to provide a FormatStyle as a parameter to be able to use the function.
This FormatStyle is a protocol that has two associated types: an input and an output. In this case, the input needs to be a Date type. Lucky for us, Swift already provides us with a struct that conforms the FormatStyle protocol that we need: Date.FormatStyle. This FormatStyle has a static variable dateTime: Date.FromatStyle
that we can use as a function's parameter directly.
We now have a FormatStyle instance that we can customize using the Date.FormatStyle’s instance methods (you can check the list in the official documentation). Let’s see a couple of examples.
Here we take dateTime variable (which is a Date.FromatStyle instance) and call month, day and year function. All three functions return a Date.FromatStyle type, which is the type that the function’s parameter expects. We’re just manipulating the format. There’re plenty of combinations that we can achieve using these instance methods.
Be aware that the order we call the functions doesn’t affect the final output. Swift does the heavy work for us and decides the correct format based on the user’s preferences.
Now imagine that we need to send a String Date to our backend with a specific format? (like “2021–07–18”). For this scenario, we’ll need to use option number three. Like the Date.FormatStyle, ISO8601FormatStyle has a static variable for us to use, iso8601. This format function is pretty much like the one we just saw before but with some extra configurations available.
With ISO8601FormatStyle we can specify the date separator that we want to use.
Now, if we are only interested in showing a Date String, but we don’t have specific requirements regarding the formatting, we can use our last option (number four) and some pre-defined formats. Both Date.FormatStyle.DateStyle and Date.FormatStyle.TimeStyle provide us with several static constants ready to use.
The last missing part is the reverse one, how do we create a Date type from a String with a specific format? For this we must use the new Date initializer:
We have to pass the function a String (which is going to be the Date in a String type with a custom format) and a strategy to parse that String. This strategy parameter must be a ParseStrategy type. Like the FormatStyle, the ParseStrategy is a protocol as well and, also has two associated types (an input and an output). The input must be a String and the output must be a Date.
The good news for us is that, like FormatStyle.Date, we already have a built-in struct that conforms the ParseStrategy protocol: Date.ParseStrategy. We only have to create a new instance to use it as a parameter inside our Date’s init function.
Let’s suppose that we are going to receive a Date String from our backend with the following format: dd-MM-yyyy (e.g. 31–01–2021). Let’s jump in and create first our ParseStrategy instance and then create a new Date instance using the parse.
As the format is a Date.FromatString type, we can use the interpolation initializer combined with the Date.FormatStyle.Symbol to create our date format.
Please be aware that at the time I’m writing this post, all these features are in beta stage and there might be changes in the official release.
I have created a cheat sheet with most of the variations that you can make with the new API. You can check it out here.