That's effectively strange at first glance, but there seems to be some logic behind.
It adds 1h at certain numbers of days : over 84, less 301
I tested your code the following values:
let durationShort: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.day, .hour, .minute]
formatter.unitsStyle = .abbreviated
formatter.zeroFormattingBehavior = .dropAll
formatter.maximumUnitCount = 3
formatter.collapsesLargestUnit = false
return formatter }()
let formattedString = durationShort.string(from: TimeInterval(86400 * 213))
print("formattedString", formattedString!)
let formattedString2 = durationShort.string(from: TimeInterval(86400))
print("formattedString2", formattedString2!)
let formattedString3 = durationShort.string(from: TimeInterval(86400 * 21))
print("formattedString3", formattedString3!)
let formattedString4 = durationShort.string(from: TimeInterval(86400 * 30))
print("formattedString4", formattedString4!)
let formattedString5 = durationShort.string(from: TimeInterval(86400 * 35))
print("formattedString5", formattedString5!)
let formattedString6 = durationShort.string(from: TimeInterval(86400 * 83))
print("formattedString6", formattedString6!)
let formattedString7 = durationShort.string(from: TimeInterval(86400 * 84)) // <<-- Adds 1h
print("formattedString7", formattedString7!)
let formattedString8 = durationShort.string(from: TimeInterval(86400 * 120))
print("formattedString8", formattedString8!)
let formattedString9 = durationShort.string(from: TimeInterval(86400 * 300))
print("formattedString9", formattedString9!)
let formattedString10 = durationShort.string(from: TimeInterval(86400 * 301)) // <<-- do not add 1h from here
print("formattedString10", formattedString10!)
let formattedString11 = durationShort.string(from: TimeInterval(86400 * 365))
print("formattedString11", formattedString11!)
I get
- formattedString 213d 1h
- formattedString2 1d
- formattedString3 21d
- formattedString4 30d
- formattedString5 35d
- formattedString6 83d
- formattedString7 84d 1h // <<-- Adds 1h
- formattedString8 120d 1h
- formattedString9 300d 1h
- formattedString10 301d // <<-- do not add 1h from here
- formattedString11 365d
It seems to do with daylight saving time
- In Europe on March 26-27, which is 1/1 + 84d (there is however a 1 day mismatch as day change is on 27 at 2 am. I did not look if GMT could explain). And winter daytime is on oct 29/30, which is 301 days after January 1st.
- in US daylight changes on March 12-13, hence day 70 of the year, and winter time on nov 6/7
- If you're in US locale, could you do the same check with values of 69 and 70 ? @69, you should get 69d and @70, you should get 70d 1h
- And 307 and 308 ? @307 you should get 307d 1h and @308 you should get 308d
So, my understanding:
- durationShort.string(from: TimeInterval) computes an endDate starting from Jan 1 of the current year
- then it evaluates the number of days and hours between startDay (1/1) and this endDate, taking daytime change into account…
However, why make duration start from Jan 1st ?
As documentation is pretty succint:
string(from:)
No overview available.
Framework
Foundation
Declaration
func string(from dateInterval: DateInterval) -> String?
It could be worth a bug report at least against documentation.