Skip to content

Fix DateTime add/subtract of weeks: 52 weeks is 364 days, not a calendar year#1790

Open
c-schuler wants to merge 1 commit into
mainfrom
fix/datetime-weeks-arithmetic
Open

Fix DateTime add/subtract of weeks: 52 weeks is 364 days, not a calendar year#1790
c-schuler wants to merge 1 commit into
mainfrom
fix/datetime-weeks-arithmetic

Conversation

@c-schuler

Copy link
Copy Markdown
Contributor

Problem

DateTime/Date arithmetic drifted by a day whenever a quantity of 52 or more weeks was added or subtracted. For example:

DateTime(2018, 5, 23) + 52 weeks // returned 2019-05-23, should be 2019-05-22

52 weeks is a fixed 364 days (and should preserve the day of week - Wed -> Wed), but the engine was returning a result 365 days later (the calendar anniversary).

Root cause

TemporalHelper.weeksToDays special-cased blocks of 52 weeks as 365-day calendar years:

if (weeks >= 52) { years = weeks / 52; weeks -= years * 52 }
return weeks * 7 + (years * 365)

This is correct for weeks < 52 (weeks * 7) but jumps by an extra day at every 52-week boundary (51 weeks → 357 days, 52 weeks → 365). A week is a fixed 7-day duration, so the year rollup has no basis in the spec.

Fix

fun weeksToDays(weeks: Int): Int = weeks * 7

Weeks are converted to days and added to the day component, letting the existing date logic walk the calendar (so leap-day/leap-year cases land correctly).

This matches the normative spec - CQL Author's Guide, Date/Time Arithmetic:

"The week, positive or negative, is multiplied by 7, and the resulting value to the day component, respecting calendar month and calendar year lengths."

(and the reference's "1 week = 7 days"), rather than any "52 weeks ~ 1 year" assumption.

Validation

  • All six DateTime add/subtract-weeks conformance tests (cql-tests) now pass, including the leap-day and leap-year variants (DateTimeAddYearInWeeks, DateTimeLeapDayAddYear, DateTimeLeapYearAddYearInWeeks, and the Subtract counterparts).
  • Full :engine:jvmTest suite passes with no regressions.

Scope

Fixes the add/subtract weeks path only. The "difference in weeks" issue (#1788 separate operator (DifferenceBetween) and is not addressed here.

Closes #1726, #1765

@c-schuler c-schuler requested review from antvaset and brynrhodes July 1, 2026 21:23
@c-schuler c-schuler self-assigned this Jul 1, 2026
@c-schuler c-schuler added the bug label Jul 1, 2026
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

Related Issues

The following open issues may be related to this PR:

Issue Title Score Matched Terms
#1763 CqlComparisonOperatorsTest "groupName": "Unit Comparison" have many failures 21.5 "cql tests", "365 days", "week days", calendar, month, correct, duration, returning, year, 365, tests, special, days, week, engine (path), org (path), cql (path)
#1766 CqlDateTime Operators does not handle precision correctly 18 "cql tests", "time arithmetic", "date time", result, datetime, time, arithmetic, correctly, tests, date, example, org (path), cql (path)
#1026 Date/time addition for partials is incorrect in some cases 18 "365 days", "date time", cases, quantity, return, added, time, converted, year, spec, 365, date, days, value
#1767 Date/DateTime add/subtract behavior 17.5 "add subtract", "date time", "datetime add", quantity, month, add, datetime, time, subtract, date, value, cql (path)
#734 Width allows Interval as a parameter 16.5 "date time", result, operator, quantity, boundary, duration, datetime, time, difference, tests, date, value, example, engine (path), org (path), cql (path)

Tip: If this PR addresses any of these issues, please link them using Closes #NNN or Refs #NNN in the PR description.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

Formatting check succeeded!

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DateTime(2018, 5, 23) add/subtract weeks returns the wrong value

1 participant