Reputation: 1365
I am trying to use NSDateComponentsFormatter
to generate user readable strings of durations. While it generally works quite well, sometimes the results are strange (or just plain wrong):
// 22d 23h 15m 34.123s
let timeInterval: NSTimeInterval = 34.123 + 60.0 * (15.0 + 60.0 * (23.0 + 24.0 * 22.0))
let formatter = NSDateComponentsFormatter()
formatter.allowedUnits = [NSCalendarUnit.Year, NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second]
formatter.maximumUnitCount = 2
formatter.unitsStyle = .Abbreviated
formatter.zeroFormattingBehavior = .Default
// expected result: 22d 23h
// actual result: 23d 16m
let result = formatter.stringFromTimeInterval(timeInterval)
Not only does it leave out the hours field in this example, but it also rounds up the days and the minutes. I would assume that once the days are rounded up, it should 'use up' the remaining minutes in the rounding. From the result, a user will think that the duration is definitely more than 23 days, while in reality it is not.
Upvotes: 1
Views: 270
Reputation: 285069
Consider that on March 27, 2016 daylight saving time changes in many countries.
The absolute time interval might not be the same as the calendar calculation based on calendar units.
Whenever possible avoid date math with literal numbers.
From the
NSDateComponentsFormatter
documentation regarding itscalendar
propertyThe formatter uses the calendar in this property to format values that do not have an inherent calendar of their own. For example, the formatter uses this calendar when formatting an NSTimeInterval value.
Update:
See also this example, it creates a date March 27, 2016, adds add one day via date components and calculates the interval
let calendar = NSCalendar.currentCalendar()
let startDate = calendar.dateWithEra(1, year: 2016, month: 3, day: 27, hour: 0, minute: 0, second: 0, nanosecond: 0)!
let endDate = calendar.dateByAddingUnit(.Day, value: 1, toDate: startDate, options: [])!
let formatter = NSDateComponentsFormatter()
formatter.allowedUnits = [.Hour, .Minute, .Second]
formatter.unitsStyle = .Abbreviated
let result = formatter.stringFromDate(startDate, toDate: endDate)
print(result) // 23h
Upvotes: 4
Reputation: 131408
Based on the limited testing I did, NSDateComponentsFormatter is buggy in iOS versions < iOS 9, and in Mac OS < 10.11.
I got flat wrong values for some date components, where it was not a rounding issue.
See my question at this link:
Getting screwy results from NSDateComponentsFormatter
Upvotes: 2