Skip to content

Fix NodaTime LocalDate subtraction and BCE year extraction - #4109

Merged
roji merged 3 commits into
mainfrom
roji-nodatime-date-triage
Oct 25, 2026
Merged

roji merged 3 commits into
mainfrom
roji-nodatime-date-triage

Conversation

@roji

@roji roji commented Oct 25, 2026 •

Copy link
Copy Markdown
Member

LocalDate - LocalDate currently constructs an interval containing only elapsed days, losing the calendar years and months returned by NodaTime. Translate it to PostgreSQL age() instead, casting both operands to timestamp without time zone to avoid time zone-dependent arithmetic.

This changes observable period components: December 31 to January 31 now returns P1M rather than P31D. PostgreSQL's month-end semantics still differ from NodaTime's; for example, January 31 to February 28 in a non-leap year returns P28D rather than P1M. This intentionally uses native PostgreSQL semantics instead of complex exact emulation.

Adds coverage for calendar components, negative periods, and the accepted month-end difference, and updates existing SQL baselines. All 219 NodaTime translation tests pass.

Fixes #4089

Return calendar years, months and days instead of an elapsed-day interval. Cast operands to timestamp to avoid time zone dependence and cover calendar components, negative periods and month-end differences.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 25, 2026 09:03

Copilot AI 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.

🟢 Approval recommended

The focused translation and regression coverage match the intended PostgreSQL semantics, with no blocking issues identified in static review.

No open issues 🎉

What changed in this PR

Updates the PostgreSQL provider’s NodaTime LocalDate subtraction to return calendar period components using age(). This partially addresses #4089; the BCE .Year issue remains out of scope.

Changes:

  • Replaces day-only interval construction with age(), casting both operands to timestamps without time zones.
  • Adds tests for calendar components, negative periods, and the intentional PostgreSQL month-end behavior.
  • Updates existing subtraction SQL baselines.
File Description
test/​EFCore.PG.FunctionalTests/​Query/​Translations/​NodaTime/​LocalDateTranslationsTest.cs Adds period regression coverage and updates SQL assertions.
src/​EFCore.PG/​Query/​Internal/​NpgsqlSqlTranslatingExpressionVisitor.cs Translates LocalDate subtraction using age() with explicit timestamp casts.

Review effort: Balanced

Correct negative PostgreSQL date/time years to NodaTime astronomical numbering without changing Period.Years or LocalDate subtraction.

Partially addresses #4089.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 25, 2026 09:11
@roji roji changed the title Translate NodaTime LocalDate subtraction using age() Fix NodaTime LocalDate subtraction and BCE year extraction Oct 25, 2026

Copilot AI 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.

🟢 Approval recommended

The focused translations and regression coverage match the intended behavior, with no blocking issues identified in static review; tests were not independently executed.

No open issues 🎉

Review effort: Balanced

Use trunc(year - 0.5) + 1 to adjust BCE years with a single date_part call, and update SQL baselines.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 25, 2026 11:59
@roji
roji enabled auto-merge (squash) October 25, 2026 12:01

Copilot AI 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.

🟢 Approval recommended

The focused translation changes and regression coverage match the intended semantics, with no unresolved blocking issues.

No open issues 🎉

Review effort: Balanced

@roji
roji merged commit c913c54 into main Oct 25, 2026
16 checks passed
@roji
roji deleted the roji-nodatime-date-triage branch October 25, 2026 12:14
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.

NodaTime: LocalDate - LocalDate returns days only, and .Year of BCE dates is off by one

2 participants