Bug in Calendar.date(from:) in iOS 18? It is now underspecified with year, weekOfYear, and yearForWeekOfYear?

One of our apps has some failing unit tests that I traced back to a change in the way Calendar.date(from:) works on iOS 18 beta (22A5307d) as compared to earlier versions. The simple demo unit test below passes in iOS 17.5 and fails in 18 beta 3. I did not test this in other beta versions.

import XCTest

final class DateComponentsMath_Tests: XCTestCase {
        func testAddingWeek() throws {
        var components = DateComponents(
            year: 2024,
            weekOfYear: 1,
            yearForWeekOfYear: 2024
        )
        let date1 = Calendar.current.date(from: components)!
        
        // add a few weeks to the components
        components.weekOfYear = components.weekOfYear! + 5
        let date2 = Calendar.current.date(from: components)
        
        XCTAssertNotEqual(date1, date2, "We added five weeks to the components so this should not result in the same date")
    }
}

It appears that in iOS 18 (22A5307d), year, weekOfYear, and yearForWeekOfYear are no longer enough to uniquely specify a date. With those three values, Calendar.date(from:) always returns January 1 of the specified year. In earlier versions of iOS this was not the case.

I submitted this as FB14323984

Answered by DTS Engineer in 795540022
I submitted this as FB14323984

Thanks for filing that. Foundation is getting a serious makeover this year, so I’m not super surprised to see an issue like this. Filing a bug is definitely the right path forward here.

However, I’m curious about the code you posted. You specify both the year and yearForWeekOfYear components, which seem contradictory. The year component is used when you’re doing year/month/day calculations and the yearForWeekOfYear component is used when you’re doing year/week-of-year/day-within-week calculations. Apply both is weird, and you could imagine it causing problems because some days at the beginning and end of the year can have different values for these components.

So, what happens if you drop the year component from your test?

Share and Enjoy

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

Accepted Answer
I submitted this as FB14323984

Thanks for filing that. Foundation is getting a serious makeover this year, so I’m not super surprised to see an issue like this. Filing a bug is definitely the right path forward here.

However, I’m curious about the code you posted. You specify both the year and yearForWeekOfYear components, which seem contradictory. The year component is used when you’re doing year/month/day calculations and the yearForWeekOfYear component is used when you’re doing year/week-of-year/day-within-week calculations. Apply both is weird, and you could imagine it causing problems because some days at the beginning and end of the year can have different values for these components.

So, what happens if you drop the year component from your test?

Share and Enjoy

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

I agree that the test is odd. In our app we are generating a sequence of all of the start dates for weeks within a year by iterating over weekOfYear. Somehow we ended up with both year and yearForWeekOfYear specified (probably because year alone didn't give us the results we wanted). Dropping the year does indeed generate the same sequence of results as including it in both iOS 17 and 18 beta so it looks like we just make that change and are good.

It seems to me that Calendar.date(from:) should return nil for cases where year and yearForWeekOfYear are specified, rather than January 1 of the specified year.

Cheers!

I’m glad to hear you’re making progress. I’d appreciate you updating FB14323984 with the latest info.

It seems to me that Calendar.date(from:) should return nil for cases where year and yearForWeekOfYear are specified, rather than January 1 of the specified year.

In theory, I agree. In practice, it’s hard to make a change like that because it’d break existing code. I think the most likely resolution here is that we’ll get back to where we were in iOS 17.

Share and Enjoy

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

I updated FB14323984 with the details above. Thanks for your thoughts. I agree that given that the old date(from:) behavior was already used by devs in the field (including us!) that it should be maintained.

What I should have said was that if a change in functionality was going to happen, then it should return nil, not January 1.

Bug in Calendar.date(from:) in iOS 18? It is now underspecified with year, weekOfYear, and yearForWeekOfYear?
 
 
Q