Skip to content

Compute the Gregorian quarter from the month - #2364

Open
alphasafal wants to merge 2 commits into
swiftlang:mainfrom
alphasafal:fix-calendar-quarter
Open

alphasafal wants to merge 2 commits into
swiftlang:mainfrom
alphasafal:fix-calendar-quarter

Conversation

@alphasafal

Copy link
Copy Markdown

Compute the Gregorian quarter from the month.

Motivation:

_CalendarGregorian.dateComponents derived .quarter from a 1-based dayOfYear using 0-based thresholds (< 90 / < 181 / < 273, and the leap-year variants). As a result the last day of Q1, Q2 and Q3 — March 31, June 30 and September 30 — was reported as the next quarter, every year. ordinality(of: .quarter, in: .year, for:) and dateInterval(of: .quarter, for:) already compute quarters from the month and disagree with dateComponents on these days.

Fixes #2363

Modifications:

  • Replace the leap / non-leap day-of-year tables with (month - 1) / 3 + 1, matching ordinality and dateInterval.
  • Add quarterAtQuarterBoundaries, which checks the first and last day of every quarter in a non-leap (2023) and a leap (2024) year.

Result:

March 31, June 30 and September 30 report Q1, Q2 and Q3. dateComponents, ordinality and dateInterval now agree.

Testing:

The new test fails on main (6 failures) and passes with the fix on Linux; the rest of the suite passes on Linux, Windows, and the Android and Wasm builds.

@alphasafal
alphasafal requested a review from a team as a code owner October 26, 2026 09:22

@parkera parkera left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable, although I'm curious why we chose to derive quarter from day rather than month in the first place. @itingliu / @dra8an ?

@parkera

parkera commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

@swift-ci test

@alphasafal

Copy link
Copy Markdown
Author

Thanks @itingliu for cross-checking, and thanks @niktishakov for closing #2319 in favour of this one. You found the same root cause first. On @parkera's question: as far as I can tell, quarter wasn't meant to come from the day of year. The quarter bounds were compared against a 1-based day-of-year as if it were 0-based, which has been off by one since #303. Deriving it from the month matches ordinality and dateInterval. I'm happy to fold in #2319's change to skip computing dayOfYear when only .quarter needs it, if you'd like that here.

@itingliu

Copy link
Copy Markdown
Contributor

Thanks @itingliu for cross-checking, and thanks @niktishakov for closing #2319 in favour of this one. You found the same root cause first. On @parkera's question: as far as I can tell, quarter wasn't meant to come from the day of year. The quarter bounds were compared against a 1-based day-of-year as if it were 0-based, which has been off by one since #303. Deriving it from the month matches ordinality and dateInterval. I'm happy to fold in #2319's change to skip computing dayOfYear when only .quarter needs it, if you'd like that here.

If you don't mind doing that, please do! Thanks and thank you @niktishakov too

The quarter now comes from the month, so dayOfYear is only needed for
.dayOfYear, .weekOfYear and .yearForWeekOfYear.

Picked up from swiftlang#2319 at @itingliu's request.
@alphasafal

Copy link
Copy Markdown
Author

Done in 78db4ca: dayOfYear is now only computed for .dayOfYear, .weekOfYear and .yearForWeekOfYear. Thanks @niktishakov for the original change.

@alphasafal

Copy link
Copy Markdown
Author

@itingliu @parkera the dayOfYear change from #2319 is in 78db4ca. I don't see a CI run on the new commit; could one of you trigger it again when you get a chance?

@parkera

parkera commented Nov 11, 2026

Copy link
Copy Markdown
Contributor

Looks like some kind of infra issue on the tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Calendar returns the wrong quarter on March 31, June 30 and September 30

3 participants