In Bite #287, we built a small extension to Date to allow us to format relative date strings like "10 minutes ago". We used a bunch of if statements and built our final String. This was a nice way to learn about working with DateComponents, but it turns out πŸ›Ž  Foundation actually provides a class to do something similar, and it's much more powerful.

Today we'll continue our look at Foundation's date and time-related functionality with DateComponentsFormatter. Let's dive in.

Much like its cousin DateFormatter (Bite #286), DateComponentsFormatter is all about converting a TimeInterval or DateComponents into a nicely formatted, human-readable String. (Note: It doesn't support parsing Strings yet. Conversions are a one way trip for now).

We'll start with a new formatter:

let formatter = DateComponentsFormatter()

Then we'll configure a few options:

formatter.unitsStyle = .full
formatter.allowedUnits = [.minute, .second]

And finally, we'll ask for a String describing an example TimeInterval:

formatter.string(from: 543.0) // "9 minutes, 3 seconds"

Like many Foundation types, DateComponentsFormatter is a super customizable powerhouse. Let's try a few more options:

formatter.unitsStyle = .abbreviated
formatter.string(from: 123.0)

// "2m 3s"
formatter.unitsStyle = .short
formatter.string(from: 123.0)

// "2 min, 3 sec"
formatter.unitsStyle = .spellOut
formatter.string(from: 123.0)

// "two minutes, three seconds"
formatter.includesApproximationPhrase = true
formatter.includesTimeRemainingPhrase = true
formatter.unitsStyle = .brief
formatter.string(from: 123.0)

// "About 2min 3sec remaining"

Neat. Fun Fact: If you've ever seen a progress bar or "time remaining" bar in iOS or macOS, you've seen a DateComponentsFormatter in action.

We've only been allowing .minutes and .seconds. Let's try allowing some different sets of units:

let formatter = DateComponentsFormatter()

formatter.unitsStyle = .full

formatter.allowedUnits = [.minute, .second]
formatter.string(from: 1234567.0)

// "20,576 minutes, 7 seconds"
formatter.allowedUnits = [.day, .hour, .minute, .second]
formatter.string(from: 1234567.0)

// "14 days, 6 hours, 56 minutes, 7 seconds"
formatter.allowedUnits = [.day, .minute, .second]
formatter.string(from: 1234567.0)

// "14 days, 416 minutes, 7 seconds"

Neat!

These are just the very basics. Look out for some more advanced DateComponentsFormatter fun soon.