With Swift's relatively new Duration feature, there are pre-created common patterns (.hourMinute, .hourMinuteSecond, and .minuteSecond) for formatting Durations that handle hours and minutes of time, but the formats don't work for times that are just seconds or are greater than a day.
How do I create a custom TimeFormatStyle pattern that allows me to show some amount of time that is less than a minute such as 9 seconds and 54 hundredths of a second as simply "9.54"? I would need to have control over the padding of the seconds so that I could optionally format to "09.54" and I would want to round milliseconds rather than truncate them, so 9 seconds and 541 milliseconds should format as "9.54" and 9 seconds and 547 milliseconds should format as "9.55".
As you just want to format it as a number, you can write your own FormatStyle
that wraps one of the existing format styles for numbers (e.g. FloatingPointFormatStyle
), with a FormatInput
being Duration
. You can then convert the Duration
to a number of seconds in the format
method.
Here I have wrapped a Decimal.FormatStyle
, just because Duration
is represented in a base-10 way.
struct SecondsOnlyFormatStyle: FormatStyle {
let numberFormat: Decimal.FormatStyle
func format(_ value: Duration) -> String {
let (seconds, attoseconds) = value.components
let decimal = Decimal(seconds) + Decimal(attoseconds) / 1e18
return numberFormat.format(decimal)
}
}
// extension on FormatStyle so that you don't need to write "SecondsOnlyFormatStyle"
// when there is already a contextual type, just like other format styles.
extension FormatStyle where Self == SecondsOnlyFormatStyle {
static var secondsOnly: SecondsOnlyFormatStyle {
.init(numberFormat: .number)
}
static func secondsOnly(integerLength: Int, fractionalLength: Int) -> SecondsOnlyFormatStyle {
.init(numberFormat: .number.precision(.integerAndFractionLength(integer: integerLength, fraction: fractionalLength)))
}
}
Usage:
Text(someDuration, format: .secondsOnly(integerLength: 2, fractionalLength: 2))