Converting Date to String and back
Tags: swift, ios, xcode, iphone
Published: 2022-04-03 17:04:28

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

![scary image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8fpabyvrt3d6o84qquq5.jpg)

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][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 ↙️

```swift
var today = Date()
print(today)

// 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.

The most common standard or **standard standard** is **ISO 8601**, and this is how it is constructed

![ISO](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wr0qqdssa4uuwb1grqz4.png) 

And now all of that makes complete sense. Except for 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*.

```swift
// 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 <em>.current</em> for the <em>.locale</em> 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 ⬇️

```swift
// 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? 🤷‍♂️

```swift
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. ⬇️

---

<table style="width:50%">
<tr>
<th>Input</th>
<th>Output</th>
</tr>
<tr>
<td>MMM</td>
<td>Jan</td>
</tr>
<tr class="even">
<td>MM</td>
<td>01</td>
</tr>
<tr>
<td>M</td>
<td>1</td>
</tr>
<tr class="even">
<td>d</td>
<td>9</td>
</tr>
<tr>
<td>dd</td>
<td>09</td>
</tr>
<tr class="even">
<td>y</td>
<td>2007</td>
</tr>
<tr>
<td>yy</td>
<td>07</td>
</tr>
<tr class="even">
<td>yyy</td>
<td>2007</td>
</tr>
<tr>
<td>yyyy</td>
<td>2007</td>
</tr>
<tr class="even">
<td>HH:mm</td>
<td>17:41</td>
</tr>
<tr>
<td>hh:mm</td>
<td>05:41</td>
</tr>
<tr class="even">
<td>hh:mm a</td>
<td>05:41 PM</td>
</tr>
<tr>
<td>E</td>
<td>Tue</td>
</tr>
</table>

---

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.

```swift
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][twitter]

Cheers! 🍻

[computerfile]: https://www.youtube.com/watch?v=-5wpm-gesOY&t=2s
[twitter]: https://twitter.com/emin_roblack