Repository navigation
Lite: Queries-tab comparisons read the grid's UTC window, not a server-shifted one (#4284) - #4302
Merged
Merged
Conversation
GetQueryStatsComparisonAsync/GetProcedureStatsComparisonAsync/GetQueryStoreComparisonAsync compare their bounds straight against UTC collection_time. A custom range and a slicer drag both used to hand them a server-local window instead, shifting the comparison by the server's UTC offset on any server not on UTC. - GetComparisonRange(DateTime, DateTime) now takes the current UTC window and shifts it, backed by a static ShiftComparisonRange helper for testability. - CompareToCombo_SelectionChanged and the six ServerTab.Refresh.cs call sites compute the UTC window once (LocalDataService.GetQueriesTabWindowUtc) and hand it to both the comparison and the banner. - The three slicer handlers pass the comparison e.StartUtc/e.EndUtc instead of the server-local fromServer/toServer. - RefreshOverviewAsync (correlated lanes) is decoupled from GetComparisonRange and keeps its byte-identical prior derivation, since its own lane reads take server-local fromDate/toDate, not UTC. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
erikdarlingdata
marked this pull request as ready for review
September 25, 2026 15:26
erikdarlingdata
enabled auto-merge (squash)
September 25, 2026 15:26
This was referenced Sep 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #4284.
Why
Lite stores
collection_timein UTC. The Queries tab's three comparison reads(
GetQueryStatsComparisonAsync,GetProcedureStatsComparisonAsync,GetQueryStoreComparisonAsync)compare their start and end times straight against it, with no offset conversion of their own. Two
callers handed them a server-local window instead of UTC:
e.StartUtc/e.EndUtcto server time (fromServer,toServer). It passedthose to the comparison. The grid read beside it converted back to UTC.
cStart/cEndfrom the date pickers in server time, andGetComparisonRange()built its own baseline the same way.So on a server not on UTC, the comparison read a window shifted by the server's offset. After a
slicer drag, the current window was shifted but the baseline (from a preset range) was not.
What changes
GetComparisonRange(Lite/Controls/ServerTab.Comparison.cs) now takes the caller's current UTCwindow and shifts it back. Yesterday shifts it 1 day, and Last week and Same day last week shift it 7 days.
Before, it independently recomputed its own current window from UI state. The shift itself moved
into a static
ShiftComparisonRange(int selectedIndex, DateTime currentStart, DateTime currentEnd)helper, so a test can drive it without constructing the WPF control.
CompareToCombo_SelectionChangedand the six comparison call sites inServerTab.Refresh.cscompute the UTC window once. They use
LocalDataService.GetQueriesTabWindowUtc, the helperLite MCP tools disclose a truncated query-stats window (#4231) #4279 added for the "Showing since" banner. That one tuple goes to both the comparison call and
the banner call beside it.
OnXSlicerChangedhandlers inServerTab.Slicers.cspass the comparisone.StartUtc/e.EndUtc, the same UTC bounds the banner already used. Before, they passed the server-localfromServer/toServerthat the grid read uses.IsQueryStatsComparisonActivenow testsCompareToCombo.SelectedIndexdirectly, sinceGetComparisonRangeneeds a current window to call.shifted back, not the whole preset range shifted back. The current and baseline windows always
cover the same span.
QueryStatsComparisonBannerand its two siblings) fixthemselves.
ServerTimeHelper.FormatServerTimeexpects UTC and adds the server's offset once.Before this fix, a custom-range baseline was already server-local, so the banner silently
double-shifted it.
ViewerServerTab.QueriesComparison.cs) already passes UTCwindows to its comparisons, so it needs no change.
Overview tab (correlated lanes) is deliberately left alone, with a filed follow-up
GetComparisonRange()had a second caller:RefreshOverviewAsync's correlated-lanes ghost-linecomparison (Tab 0). That comparison's own reads (
GetCpuUtilizationAsync,GetTotalWaitTrendAsync,and others) take
fromDate/toDatein server-local time, not UTC. That is the opposite contract fromthe three Queries-tab comparison reads this issue is about.
That caller is not built to use a UTC window.
So
RefreshOverviewAsyncnow derives its own range inline, in the sameserver-local basis it always used. That derivation is byte-identical to its pre-fix version. It just
reuses the pure
ShiftComparisonRangeday-shift arithmetic instead of duplicating it.That leaves one pre-existing, narrower bug in place. Under a preset (non-custom) range on a server not
on UTC,
RefreshOverviewAsyncstill hands the lanes aDateTime.UtcNow-based window. Theirserver-local readers then shift it again.
A real fix needs to touch the ghost-line X-axis time-shift
math inside
CorrelatedTimelineLanesControl.RefreshAsyncitself. That code has no testcoverage and no Darling version to copy. Darling's viewer never ported this overlay, on purpose
(see the "Deliberately dropped for v1" comment in
CorrelatedTimelineLanesControl.xaml.cs). Filed as#4296.
Test plan
Lite.Tests/Lite.Tests.csprojbuilds with 0 warnings.Lite.Tests/ComparisonWindowUtcTests.cs. A[Theory]over UTC+5 and UTC-7 pinsShiftComparisonRange's day-shift: 1 and 7 days, same span, basis-agnostic. A source-scan testpins that every comparison call site takes a UTC bound, not
fromServer/toServeror acStartbuilt fromfromDate. It also pins that the sixServerTab.Refresh.cscomparisoncalls share the identical
windowStart/windowEndtuple the banner call beside them uses.(
QueryWindowTruncationTests.WindowTruncatedBannerCallSites_TakeUtcBounds_NotServerLocalOnes,Lite.Tests/QueryWindowTruncationTests.cs). Its regex expected the oldbannerStart/bannerEndnames. Renamed to matchwindowStart/windowEndand corrected its now-stale claimthat the comparison call stays untouched.
Lite/Controls/ServerTab.*.csfiles toorigin/dev, then reranComparisonWindowUtcTestsandQueryWindowTruncationTests. Both new/updated assertions failed, as expected. Restored withgit checkout HEAD.ComparisonWindowUtcTests,QueryWindowTruncationTests): 14passed, 0 failed.
origin/dev, no conflicts. FullLite.Tests.exerun once: 5389 total, 0 failed, 0errors.
CHANGELOG entry
SECTION: Fixed
ENTRY:
REF:
[Lite: Queries-tab comparisons read the grid's UTC window, not a server-shifted one (#4284) #4302]: Lite: Queries-tab comparisons read the grid's UTC window, not a server-shifted one (#4284) #4302
🤖 Generated with Claude Code
https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ