iOS Bite: DateComponentsFormatter

By Jason Connery

May 10, 2024 at 10:10

ios-bites

DateComponentsFormatter

You have a number of seconds representing an amount of time. Not a timestamp, but a duration.

How would you turn 478 seconds into 00:07:58? Or 47478 seconds into 13:11:18?

Like many before you…

func myTimeFormatter(timeInSec: Int) -> String {
        let hours: Int = timeInSec / 3600
        let hoursRemainder: Int = timeInSec % 3600
        let minutes: Int = hoursRemainder / 60
        let minsRemainder: Int = hoursRemainder % 60
        let seconds: Int = minsRemainder % 60
        return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
}
myTimeFormatter(timeInSec: 478) // 00:07:58

It works - 00:07:58 - but with 5 magic variables, and several assumptions on padding and units.

I’m willing to bet programmers across the verse have written this many times.

Or Use DateComponentsFormatter

let defaultFormatter = DateComponentsFormatter()
defaultFormatter.string(from: 478)
// 7:58

Wait … that’s not even close. There’s no leading zeros. I need those - design requires them for alignment, and to make it clear its not 7 hours 58 minutes or something.

So I should continue to build my own formatter, yes?

Don’t worry, we have options

let withPaddingFormatter = DateComponentsFormatter()
withPaddingFormatter.allowedUnits = [.hour,.minute,.second]
withPaddingFormatter.zeroFormattingBehavior = .pad

withPaddingFormatter.string(from: 478)
//00:07:58

We can be specific on the units we want, and set padding behaviour to keep leading zeros, design dependent.

This is still less custom formatting.

But what about… ?

Actually, I also need something like 7m 58s. Or maybe 7 min 58s?

What if I need to show a remaining time?

What if I need it in a more natural language?

let withTextFormatter = DateComponentsFormatter()
//can include days, months also
withTextFormatter.allowedUnits = [.hour,.minute,.second]

withTextFormatter.unitsStyle = .abbreviated
withTextFormatter.string(from: 478) 
//7m, 58s

withTextFormatter.unitsStyle = .brief
withTextFormatter.string(from: 478) 
//7min, 58seconds

withTextFormatter.unitsStyle = .full
withTextFormatter.string(from: 478) 
//7 minutes, 58 seconds

withTextFormatter.unitsStyle = .spellOut
withTextFormatter.string(from: 478) 
//"seven minutes, fifty-eight seconds"

withTextFormatter.unitsStyle = .abbreviated
withTextFormatter.includesApproximationPhrase = true
withTextFormatter.includesTimeRemainingPhrase = true
withTextFormatter.string(from: 478) 
//About 7m 58s remaining

Last updated: May 10, 2024 at 10:10