Emin Grbo, Apr 22 2020

Converting Date to String and back

There you are, coding away, all is fine, birds are chirping, keys are not getting stuck on your 2018 MBPro...but in the distance, Date() approaches . . .

Jokes aside dates are not that hard to work with most of the time. Accuracy isn't that important for majority of apps, but if you go down the rabbit hole of dates, there is no telling where you might end up.

Computerfile said it best in this video, so do check it out as it is quite fun and it will gives you a bit more insight.

If you create a Date() in your code, and print it, you will get something like so ↙️

var today = Date()

// prints -> "2020-04-22 19:34:58 +0000"

When working with an API you will most probably get 2020-04-22T19:34:58+0000

Looks like a long string of...something...right? But fear not, it's actually very well structured, and quite logical once you know what to look for.

Most common standard or standard standard is ISO 8601, and this is how it is constructed

And now all of that makes complete sense. Except that Z thing. Like...Zee UTC? 🤪

Get that Date!

Now that we know what we are looking at, first, we need to convert String -> Date.

// Info we got from backend.
let stringDateFromAPI = "2007-01-09T09:41:00-0700"

// Creating a formatter and setting the current locale
let formatter = DateFormatter()
formatter.locale = .current

// Telling the formatter what what kind of format we are expecting.
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"

// Creating the date object
let dateFromAPI = formatter.date(from: stringDateFromAPI)

print(dateFromAPI ?? "Unknown")
// 🖨 2007-01-09 16:41:00 +0000 // But now its a date, not a string.

We got our Date() all nice and tidy. From here on, we have LOADS of choices for time formatting.

Keep in mind that the hours and minutes are based on the current user location since we used .current for the .locale setting. In case that you want to use the source time, just omit that formatter setting.

This date can be converted to a proper string now, in various ways. Here I will show you 2 main approaches that I use:

Going Native  (⌥#1)

Swift DateFormatter already has some pre-defined formats that might get the job done. Take a look at the print output for each. If you don't need a lot of control of your date, feel free to use these ⬇️

// Since dateFromAPI is an optional Date,
// I am using todays date as a default.

let nativeFormatter = DateFormatter()
nativeFormatter.locale = .current

nativeFormatter.dateStyle = .full
print(nativeFormatter.string(from: dateFromAPI ?? Date()))
// 🖨 Tuesday, January 9, 2007

nativeFormatter.dateStyle = .long
print(nativeFormatter.string(from: dateFromAPI ?? Date()))
// 🖨 January 9, 2007

nativeFormatter.dateStyle = .medium
print(nativeFormatter.string(from: dateFromAPI ?? Date()))
// 🖨 Jan 9, 2007

nativeFormatter.dateStyle = .none
print(nativeFormatter.string(from: dateFromAPI ?? Date()))
// 🖨

nativeFormatter.dateStyle = .short
print(nativeFormatter.string(from: dateFromAPI ?? Date()))
// 🖨 1/9/07

Custom Formatting 🛠 (⌥#2)

In case you need a more granulated control, just create your own custom formatter. Maybe even add some emojis to it? 🤷‍♂️

let customFormater = DateFormatter()
customFormater.locale = .current
customFormater.dateFormat = "🗓 MMM d yyyy 📲"
print(customFormater.string(from: dateFromAPI ?? Date()))
// 🗓 Jan 9 2007 📲

When creating a custom format, pay attention which notation you are using for the .dateFormat. It can get a wee bit touchy feely.

For example, lower-caps m is used for minutes, while capital M for months. Here are some examples below and their output. ⬇️

Input Output
MM 01
M 1
d 9
dd 09
y 2007
yy 07
yyy 2007
yyyy 2007
HH:mm 17:41
hh:mm 05:41
hh:mm a 05:41 PM
E Tue

You are now able to mix-n-match to create your custom DateFormatter!

You will fear the dates no longer!

As promised, here is the extension on String you can use for your projects and handle most API responses.

extension String {
    func convertToReadableDate() -> String? {
        let formatter = DateFormatter()
        formatter.locale = .current
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
        guard let dateFromAPI = formatter.date(from: self) else { return nil}
        formatter.dateFormat = "MMM d yyyy"
        return formatter.string(from: dateFromAPI)

// Usage: 
// label.text = "someDateString".convertToReadableDate()

Thank you for reading! Feel free to get in touch on Twitter

Consider subscribing to the newsletter below if you loved the content. I am so lazy I probably won't bore you more than once a week.

Cheers! 🍻

Tagged with: