How to format a time interval with the new Foundation formatted method?
Asked Answered
R

1

6

I'm trying to use the new Foundation formatters. To format a Date, I can do something like this:

Date.now.formatted(.dateTime.hour().minute().second())
// 5:03:17 PM

However, I'm trying to use this new API to replace the DateComponentsFormatter:

let duration: TimeInterval = 0

let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
formatter.allowedUnits = [.minute, .second]
formatter.zeroFormattingBehavior = [.pad]

let formattedDuration = formatter.string(from: 0)
// 00:00

How can I use the new Foundation formatters API formatted instead of DateComponentsFormatter?

Reive answered 11/7, 2022 at 21:3 Comment(3)
TimeInterval is not a dateCoelenteron
The DateComponentsFormatter can accept a TimeInterval and was wondering how to use the new Foundation formatter.Reive
Did you check in the new beta? I never found a way to do this in iOS 15 but I assumed this would be fixed in a future version...Unbending
C
22

AFAIK the formatted method for a time interval only works with Duration objects which needs to be initialized with a timeval:

let timeInterval: TimeInterval = 125.0
let tmv = timeval(tv_sec: Int(timeInterval), tv_usec: 0)
Duration(tmv)
    .formatted(.time(pattern: .hourMinuteSecond))  // "0:02:05"
Duration(tmv)
    .formatted(.time(pattern: .minuteSecond))      // "2:05"

or

Duration(
    secondsComponent: Int64(timeInterval),
    attosecondsComponent: 0
).formatted(.time(pattern: .minuteSecond))  // "2:05"

You can also use its static methods for initialization:

let timeInterval: TimeInterval = 125.0
var duration: Duration = .seconds(timeInterval)
duration += .milliseconds(789)  // 125.789 seconds
    
duration.formatted(.time(pattern: .minuteSecond))  // "2:06"

And if you need further customization:

duration.formatted(.time(pattern: .minuteSecond(padMinuteToLength: 2)))  // "02:06"
duration.formatted(.time(pattern: .minuteSecond(padMinuteToLength: 2, roundFractionalSeconds: .down)))  // "02:05"
duration.formatted(.time(pattern: .minuteSecond(padMinuteToLength: 2, fractionalSecondsLength: 3)))  // "02:05.789"
Coelenteron answered 11/7, 2022 at 22:29 Comment(2)
Good find! Bummer it's iOS 16+ but still happy about this.Reive
Works with iOS 16+ / macOS 13+Meill

© 2022 - 2025 — McMap. All rights reserved.