shim
shim

Reputation: 10116

DateComponentsFormatter time duration string shows leading zero (e.g. "01" minutes) if re-using formatter

I use a DateComponentsFormatter to get a String to display a TimeInterval. In this particular case I want to show only minutes and hours (if an hour or greater).

But if I use the same instance of DateComponentsFormatter (trying to prevent repetitive re-initialization, using a lazy var) and first call the method with a duration greater than or equal to an hour, the second time if it's called with a value less than 10 minutes it always has a leading zero.

class DurationStringHelper {
    private lazy var timeFormatter: DateComponentsFormatter = {
        let formatter = DateComponentsFormatter()
        formatter.zeroFormattingBehavior = .dropLeading
        formatter.allowedUnits = [.hour, .minute]

        return formatter
    }()

    public func duration(seconds: TimeInterval) -> String {        
        return timeFormatter.string(from: seconds)!
    }
}

// CASE 1:
let c1 = DurationStringHelper()
c1.duration(seconds: 3600) // "1:00"
c1.duration(seconds: 60) // "01"  ARGH WHY GOD WHY!!!

// CASE 2: (first call less than an hour)
let c2 = DurationStringHelper()
c2.duration(seconds: 3599) // "59"
c2.duration(seconds: 60) // "1"

My current approach is just to check if there's an unwanted leading zero (checking for the presence of the character and checking whether the seconds falls into a certain range) and removing it. This is an ugly hack though.

This seems like a bug to me, so I submitted a report to Apple. Don't see why one call to a formatter should affect later calls.

Note: the same thing doesn't seem to happen if you include .day in allowed units, and first call it with a time interval of a day or more, and then again with less than 10 hours. Although it does happen if you set allowedUnits to [.minute, .second] and then call it first with 60 seconds and then with 9 seconds.

Upvotes: 1

Views: 1073

Answers (0)

Related Questions