Repository navigation
[BUG] Lite query and procedure grids render server-local DMV timestamps through the UTC formatter #3221
Description
Component
Lite
Performance Monitor Version
Confirmed in v3.6.0 source and current dev
SQL Server Version
Not version-specific; affects supported versions exposing these DMV timestamps
Windows Version
Not version-specific; Lite WPF client
Describe the Bug
Lite renders server-local plan-cache timestamps through ServerTimeHelper.FormatServerTime, whose parameter and implementation define the input as UTC. The values are therefore converted from the wrong source frame.
Confirmed affected surfaces:
- Top Queries by Duration:
Last ExecutionandCreation Time - Query execution history:
Last ExecutionandCreation Time;Collection Timeis genuinely UTC, so each row mixes correctly and incorrectly rendered frames - Top Procedures by Duration:
Last ExecutionandCached Time - Procedure execution history:
Last ExecutionandCached Time, alongside correctly UTC-basedCollection Time
The related Running Jobs, Blocking, and Active Queries timestamp defects are already reported in #3207; this report does not duplicate their details.
Source evidence
- SQL Server documents
sys.dm_exec_query_stats.creation_timeandlast_execution_timeas times in the SQL Server instance's current timezone. The corresponding procedure/function/trigger cache timestamps are likewise server-clock values. - Lite collects and stores those values without normalizing them to UTC.
- In
Lite/Services/LocalDataService.QueryStats.cs,QueryStatsRow,ProcedureStatsRow,QueryStatsHistoryRow, andProcedureStatsHistoryRowpass those stored values toServerTimeHelper.FormatServerTime. Lite/Services/ServerTimeHelper.csnames that method's inpututcTimeand first adds the server UTC offset, so its input contract is UTC.collection_timeis genuinely UTC and is correctly sent through the same formatter. That is why the history rows contain a visible mixed-frame inconsistency.
Custom-range behavior
The active tab's custom-range conversion generally reaches the correct UTC collection_time window. The rows can therefore be selected correctly while their DMV timestamps render offset from the selected Local Time range, making the range filter itself appear incorrect.
There was also a separate shared-offset custom-range defect. Its fix was merged in #2987 after v3.6.0; that fix does not change the per-column source-frame mismatch reported here.
Steps to Reproduce
Use only synthetic times; no production data is required.
- Run Lite on a workstation at UTC+02 and monitor a SQL Server at UTC-05.
- Select Local Time display mode and choose a custom range around 20:00 workstation time.
- Arrange for a cached query or procedure to execute at the equivalent instant: 18:00 UTC / 13:00 server time.
- Open Top Queries by Duration or Top Procedures by Duration, then open the corresponding execution-history grid.
- Compare
Collection TimewithLast ExecutionplusCreation TimeorCached Timefor the same interval.
Collection Time renders around 20:00 as expected. A DMV value stored as 13:00 server time is treated as 13:00 UTC; with these synthetic offsets it renders around 15:00 Local Time instead of 20:00. The discrepancy equals the server UTC offset and appears in every display mode, although the selected row still belongs to the correct UTC collection_time window.
Expected Behavior
Every timestamp is classified by its source frame and converted exactly once to the selected Local/Server/UTC display mode. For the synthetic example, timestamps describing the same instant align at 20:00 Local Time, 13:00 Server Time, or 18:00 UTC.
Actual Behavior
UTC collection_time and server-local DMV/cache timestamps use the same UTC-input renderer. Collection Time displays correctly, while Last Execution, Creation Time, and Cached Time are shifted, producing inconsistent times in the same grid or history row and making Local Time custom-range filtering appear wrong.
Error Messages / Log Output
Not applicable. This is a deterministic display-frame defect confirmed from source.
Screenshots
None. No environment-specific data is included.
Additional Context
Related renderer/frame report: #3207
Separate custom-range shared-offset fix: #2987
Activity
Pair every desktop clock render with its column's frame, in both SKUs (…
erikdarlingdata commentedon Sep 9, 2026
Claude posting for Erik Darling
Fixed, and thank you — this was a good report. It named the affected grids, distinguished the columns that were wrong from the ones that were right in the same row, and pointed at #3207 for the overlap instead of restating it. That is most of the diagnosis done before anyone read the code.
Merged to
devas7083eac0e34b; it will be in the next release.Every surface you listed is converted.
Top Queries by Duration,Query execution history,Top Procedures by DurationandProcedure execution historynow renderLast Execution,Creation TimeandCached Timethrough a renderer that expects the monitored server's own clock, instead of one whose parameter and implementation define the input as UTC. Your observation thatCollection Timewas genuinely UTC in the same row — so each row mixed a correctly and an incorrectly rendered frame — is exactly the shape that made this worth fixing rather than shrugging at: a grid where some columns are right is harder to distrust than one where none are.Two things your report led to that went beyond it.
An internal census, built while fixing #3207, found four more sites in the same file you named that neither your report nor #3207 listed —
creation_timeandcached_timein two further row types. So the Lite side of this class was wider than either account had it, and your four were the visible part of twelve.And fixing the frame turned out to introduce a separate defect on an axis nobody was watching: the corrected renderer ignored the Time Display Mode setting entirely, so selecting UTC would have shown you the server's clock anyway. That is now fixed too, and pinned — the same instant is asserted to render differently under Server and UTC mode. Had you upgraded into that intermediate state you would have traded one wrong answer for another, which is worth saying plainly since your report is what set the work in motion.
One limit, stated rather than left for you to find: the conversion uses the server's UTC offset as collected, so a timestamp from the far side of a daylight-saving boundary can be an hour out. That is a known approximation shared with the rest of the product's clock handling and not specific to these grids.
Pin the Query Store execution stamps' value wiring, machine-independe…