DateComponentsFormatter does not seem to round weeks consistently

Hi,

I'm trying to display a string containing the number of the largest given time unit for the time since as given date - i.e. "2 Months Ago" or "1 Week Ago".

DateComponentsFormatter appears to be a useful tool for this (the app targets iOS 10.2), however it doesn't seem to be formatting the number of weeks consistently.

This is how I'm setting up the formatter:
Code Block import Foundation
let day = 60*60*24
let formatter = DateComponentsFormatter()
formatter.calendar = Calendar.current
formatter.allowedUnits = [.hour, .day, .weekOfMonth, .month]
formatter.unitsStyle = .full
formatter.maximumUnitCount = 1
formatter.allowsFractionalUnits = false
formatter.zeroFormattingBehavior = .dropAll

For the given range, I would expect 8-13 to use "1 week", but this doesn't seem to be the case:
Code Block
(0..<40).forEach {
  print("\($0): \(formatter.string(from: TimeInterval(day * $0))!)")
}

The actual output of this is:

Code Block 0: 0 hours
1: 1 day
2: 2 days
3: 3 days
4: 4 days
5: 5 days
6: 6 days
7: 1 week
8: 2 weeks
9: 2 weeks
10: 2 weeks
11: 2 weeks
12: 2 weeks
13: 1 week
14: 2 weeks
15: 2 weeks
16: 2 weeks
17: 2 weeks
18: 2 weeks
19: 2 weeks
20: 2 weeks
21: 3 weeks
22: 3 weeks
23: 3 weeks
24: 3 weeks
25: 3 weeks
26: 3 weeks
27: 3 weeks
28: 4 weeks
29: 4 weeks
30: 4 weeks
31: 1 month
32: 1 month
33: 1 month
34: 1 month
35: 1 month
36: 1 month
37: 1 month
38: 1 month
39: 1 month


Could anyone point me in the right direction?
Well, that’s really weird. I initially ran your code in a macOS command-line tool project and that works as expected:

Code Block
6: 6 days
7: 1 week
8: 1 week
9: 1 week
10: 1 week
11: 1 week
12: 1 week
13: 1 week
14: 2 weeks


I was testing on on macOS 11.1.

However, the exact same code misbehaves as you described when I put it in an iOS app and run it on the iOS 14.4 simulator. That’s weird, because macOS and iOS are usually closely aligned when it comes to this sort of thing.

Honestly, I’ve no idea what’s going on here but I’m pretty certain that it’s bugworthy. Please file a bug and then post your bug number, just for the record

If you’d like help exploring workarounds, open a DTS tech support incident and I, or more likely one of my colleagues, can assist you in that context.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Hi, thanks - I've raised FB9015476.

If anyone's interested in what I've gone for as a workaround in the meantime, DateToolsSwift provides a good alternative with the timeAgoSinceNow extension to Date instances.
What is also really weird is line 13, dropping to 1 week.

12: 2 weeks
13: 1 week
14: 2 weeks



This is still broken. The following code

import Foundation

let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.allowedUnits = [.year, .month, .weekOfMonth, .day, .hour]
formatter.maximumUnitCount = 1

// Use the configured formatter to generate the string.
for i in 0..<30 {
    let seconds: TimeInterval = 24.0*3600.0*(Double(i) + 0.5)
    print("\(Double(i) + 0.5) days = \(formatter.string(from: seconds)!)")
}

produces the following output. Fractional days seem to really break things.

0.5 days = 12 hours
1.5 days = 2 days
2.5 days = 3 days
3.5 days = 4 days
4.5 days = 5 days
5.5 days = 0 months
6.5 days = 0 months
7.5 days = 1 week
8.5 days = 2 weeks
9.5 days = 2 weeks
10.5 days = 2 weeks
11.5 days = 2 weeks
12.5 days = 2 weeks
13.5 days = 1 week
14.5 days = 2 weeks
15.5 days = 2 weeks
16.5 days = 2 weeks
17.5 days = 2 weeks
18.5 days = 2 weeks
19.5 days = 2 weeks
20.5 days = 2 weeks
21.5 days = 3 weeks
22.5 days = 3 weeks
23.5 days = 3 weeks
24.5 days = 3 weeks
25.5 days = 3 weeks
26.5 days = 3 weeks
27.5 days = 3 weeks
28.5 days = 4 weeks
29.5 days = 4 weeks

This is still broken.

Indeed. While this is not fixed in macOS 13.0b1 (22A5266r), I encourage you to re-test with new betas as they are seeded.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

DateComponentsFormatter does not seem to round weeks consistently
 
 
Q