The Foundation framework makes it painless to convert a string to a date, but there are a few pitfalls you need to watch out for. The class we use to convert a string to a date in Swift is DateFormatter (or NSDateFormatter if you are using Objective-C). I encourage you to follow along with me. Fire up Xcode and create a playground.

As I mentioned in the introduction, the DateFormatter class is defined in the Foundation framework. This means we add an import statement for Foundation at the top of the playground.

import Foundation

Let's define the string we plan to convert to a Date object. We start simple. I show you a more advanced example later in this post.

import Foundation

// Create String
let string = "01/02/2016"

We create a DateFormatter instance to convert the string to a date.

import Foundation

// Create String
let string = "01/02/2016"

// Create Date Formatter
let dateFormatter = DateFormatter()

To convert the string to a date, we pass it to the date(from:) method of the DateFormatter class. Let's give that a try.

import Foundation

// Create String
let string = "01/02/2016"

// Create Date Formatter
let dateFormatter = DateFormatter()

// Convert String to Date
dateFormatter.date(from: string)

Convert a String to a Date In Swift

The method seems to work fine since we don't see any errors or warnings. The problem is that it returns nil. Something is missing.

What is missing isn't too surprising. We passed a string to the date formatter's date(from:) method without specifying the date format of the string. The DateFormatter is powerful, but it isn't magical. It cannot infer the date format of the string. That is something we need to do. Let's set the dateFormat property of the DateFormatter instance and give it another try.

import Foundation

// Create String
let string = "01/02/2016"

// Create Date Formatter
let dateFormatter = DateFormatter()

// Set Date Format
dateFormatter.dateFormat = "dd/MM/yy"

// Convert String to Date
dateFormatter.date(from: string)

This looks much better.

We need to set the dateFormat property of the DateFormatter instance.

The dateFormat property is of type String. The value you assign to the dateFormat property needs to conform to UTS or Unicode Technical Standard. The format is quite simple. Here are a few examples.

"dd/MM/yy"              // 29/10/20
"y, M d"                // 2020, 10 29
"YY, MMM d"             // 20, Oct 29
"YY, MMM d, hh:mm"      // 20, Oct 29, 02:18
"YY, MMM d, HH:mm:ss"   // 20, Oct 29, 14:18:31

Pitfalls

You always need to be careful when using the date(from:) method of the DateFormatter class. If the string you pass to the date formatter doesn't match the date format of the date formatter, then date(from:) returns nil. Take a look at this example. Can you spot the mistake?

import Foundation

// Create String
let string = "12/13/2020"

// Create Date Formatter
let dateFormatter = DateFormatter()

// Set Date Format
dateFormatter.dateFormat = "dd/MM/yy"

// Convert String to Date
dateFormatter.date(from: string) // nil

The date format of the string that is passed to date(from:) method is MM/dd/yy while the dateFormat property has a value of dd/MM/yy. In the eyes of the date formatter, the string that is passed to the date(from:) method is invalid.

This means that you should never forced unwrap the value returned by the date(from:) method. The return type is of type String?, an optional. There is a valid reason for that.

A More Complex Example

The DateFormatter class supports more complex date formats than the one we explored earlier. Take a look at this example. It includes the time and the time zone.

import Foundation

// Create String
let string = " 29 October 2019 20:15:55 +0200"

// Create Date Formatter
let dateFormatter = DateFormatter()

// Set Date Format
dateFormatter.dateFormat = "dd MMM yyyy HH:mm:ss Z"

// Convert String to Date
dateFormatter.date(from: string) // Oct 29, 2019 at 7:15 PM

More to Explore

I encourage you to explore the documentation of DateFormatter to explore the other options this class has to offer. We only scratched the surface in this post.