DateComponentsFormatter.allowsFractionalUnits does not work as advertised.

Number:rdar://32024200 Date Originated:5 May 2017
Status:Open (Duplicate of 22660145) Resolved:
Product:iOS + SDK Product Version:10
Classification:Other Bug Reproducible:Always

The documentation states that the use of DateComponentsFormatter.allowsFractionalUnits should allow output to include fractional units (like 1.5h). I cannot find any combination of flags that provide that output.

I would expect that this code would produce that output:

let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour]
formatter.allowsFractionalUnits = true
formatter.unitsStyle = .abbreviated
formatter.string(from: DateComponents(minute: 90)) // 1h

I also tried allowing minutes but restricting the maximum number of units to 1:

let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute]
formatter.allowsFractionalUnits = true
formatter.unitsStyle = .abbreviated
formatter.maximumUnitCount = 1
formatter.string(from: DateComponents(minute: 90)) // 2h

I tried to use DateComponentsFormatter.collapsesLargestUnit as well with no luck.

It looks like either the documentation is wrong (or is at least very unclear) or the implementation does not match the documented behavior.

Steps to Reproduce:
Attempt to use DateComponentsFormatter to format a fractional number of units.

Expected Results:
Provide a fractional unit to the user.

Actual Results:
Various combinations of settings either round the unit up or down to the next whole unit. Fractional units are not returned.

iOS 10, Xcode 8.3, Swift 3


iOS 10, Xcode 8.3, Swift 3


Follow up:

After doing some digging (disassembling Foundation), it looks like every call to -[_unitFormatter stringFromNumber:] in -[NSDateComponentsFormatter _stringFromDateComponents:] is passed an +[NSNumber numberWithInteger:] which drops floating point data.

A quick Objective-C example shows how this behavior could break allowsFractionalUnits:

        NSNumberFormatter *formatter = [NSNumberFormatter new];
        formatter.maximumFractionDigits = 1;

        NSNumber *first = [NSNumber numberWithInteger:5.5];
        NSLog(@"%@", [formatter stringFromNumber:first]); // 5

        NSNumber *second = [NSNumber numberWithDouble:5.5];
        NSLog(@"%@", [formatter stringFromNumber:second]); // 5.5


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!