Skip to content

fix(filter)!: convert a DateTimeOffset filter value to UTC - #143

Merged
pdevito3 merged 1 commit into
v2from
fm/qk-breaking-datetimeoffset-utc
Oct 2, 2026
Merged

pdevito3 merged 1 commit into
v2from
fm/qk-breaking-datetimeoffset-utc

Conversation

@pdevito3

@pdevito3 pdevito3 commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

For later consideration in a major version. Do not merge now. #134 restored the v1.14.2 offset to keep v1.x compatible (restore commit 7198ac2). This PR re-applies ea5cc66 for the default path. The captain decides on this PR separately.

Summary

-        { typeof(DateTimeOffset), value => ToParameterOffset(DateTimeOffset.Parse(value)) },
+        { typeof(DateTimeOffset), value => DateTimeOffset.Parse(value).ToUniversalTime() },
...
-                return FilterValue.Create(ToParameterOffset(dto), rawType);
+                return FilterValue.Create(dto.ToUniversalTime(), rawType);

ToParameterOffset is removed. Every DateTimeOffset value goes to UTC, with or without ParameterizeFilterValues.

v1.14.2 behavior (and main)

A DateTimeOffset literal keeps its offset. On main, only a parameter (with ParameterizeFilterValues on) goes to UTC, because Npgsql accepts a DateTimeOffset parameter only with offset 0.

New behavior

Every DateTimeOffset value is in UTC. The instant does not change. Only the offset and the ticks in the expression change.

Example

FilterParser.ParseFilter<TestingPerson>("SpecificDate == 2022-07-01T00:00:03+01:00");
  • v1.14.2 and main: x => (x.SpecificDate == new Nullable1(new DateTimeOffset(637922304030000000, 01:00:00)))`.
  • This PR: x => (x.SpecificDate == new Nullable1(new DateTimeOffset(637922268030000000, 00:00:00)))`.

Justification

The literal path and the parameter path must give the same value for the same input. One rule (always UTC) is simpler than a rule that depends on ParameterizeFilterValues.

Migration

None for database queries: the comparison uses the instant, and the result rows do not change. A caller that reads the expression text or the Offset of the value sees offset 0.

README

The DateTimeOffset format bullet now tells that QueryKit converts the value to UTC.

Tests

These tests come back from main before #134, in unit FilterParserTests. The expected value is in UTC again:

  • can_handle_datetime_comparison_with_timezone
  • can_handle_datetime_comparison_with_timezone_another
  • can_handle_datetime_comparison_with_negative_timezone
  • can_handle_datetime_comparison_with_timezone_no_minutes

The integration test date_time_offset_value_with_offset_matches_same_instant (Postgres) does not change. It passes with ParameterizeFilterValues off and on.

dotnet test: 470 unit tests and 297 Postgres integration tests (Testcontainers) pass, 0 failures.

Rebase on main

This branch is rebased on current main (#169). The rebase had no conflicts. The breaking change did not change.

A DateTimeOffset literal kept its offset, and only a parameter went to UTC, because Npgsql accepts a DateTimeOffset parameter only with offset 0. Convert every DateTimeOffset value to UTC, so the literal and the parameter paths give the same value. The instant does not change.

BREAKING CHANGE: a DateTimeOffset filter value is now in UTC also when ParameterizeFilterValues is off. The expression text and the offset of the value change. The instant stays the same.
@pdevito3
pdevito3 force-pushed the fm/qk-breaking-datetimeoffset-utc branch from d5cc442 to 4807fff Compare October 2, 2026 20:00
@pdevito3
pdevito3 changed the base branch from main to v2 October 2, 2026 20:00
@pdevito3
pdevito3 merged commit 5b6c151 into v2 Oct 2, 2026
2 checks passed
@pdevito3
pdevito3 deleted the fm/qk-breaking-datetimeoffset-utc branch October 2, 2026 20:02
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.

1 participant