Compare commits

...

2 Commits

Author SHA1 Message Date
rusackas
adb501a77c docs: note the now/today local-time behavior change in UPDATING.md
Adds an UPDATING.md entry per mistercrunch's review comment, flagging
that charts relying on "Now"/"Today" custom time range anchors will
compute a different (correct) timestamp after this fix, in case any
existing chart configs were tuned around the old UTC-offset bug.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 16:20:20 -07:00
Evan
05ee416103 fix(explore): resolve now/today anchors to local time, not UTC
dttmToDayjs forced "now" and "today" into UTC before formatting them
into a naive datetime string with no offset. That naive string is
later re-parsed as local time elsewhere in the same module, so the
round trip drifted by the browser's UTC offset -- the "Now"/"Midnight"
custom time range options displayed and queried the wrong wall-clock
time for anyone outside UTC.

Fixes #30627
2026-07-22 04:54:37 -07:00
3 changed files with 68 additions and 2 deletions

View File

@@ -630,6 +630,12 @@ Added a new combined datasource list endpoint at `GET /api/v1/datasource/` to se
- Semantic views are included only when the `SEMANTIC_LAYERS` feature flag is enabled.
- The endpoint enforces strict `order_column` validation and returns `400` for invalid sort columns.
### Custom time range "Now"/"Today" anchors resolve in local time
Custom time ranges that use the "Now" or "Today" anchor (for the Start, End, or the relative anchor itself) previously resolved that anchor in UTC before formatting it into a naive datetime string, which was then re-parsed elsewhere as local time. For users outside UTC, this made the resolved anchor drift by their browser's UTC offset. "Now"/"Today" now resolve directly in local time, matching the later local re-parse.
Charts and dashboards using these anchors will compute a different (correct) timestamp after upgrading; if a chart's filters or drill-downs were tuned to compensate for the old offset, review them after upgrading.
## 6.1.0
### ClickHouse minimum driver version bump

View File

@@ -0,0 +1,53 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { dttmToDayjs } from 'src/explore/components/controls/DateFilterControl/utils/dateParser';
// jest.config.js pins TZ to America/New_York (UTC-4 in June) for all unit
// tests, giving these assertions a fixed, non-zero UTC offset to catch
// UTC/local mix-ups against.
afterEach(() => {
jest.useRealTimers();
});
test('dttmToDayjs("now") resolves to the current local time, not UTC', () => {
jest.useFakeTimers();
// Midnight UTC on June 3rd is 8pm the previous day in America/New_York
// (UTC-4 during summer time).
jest.setSystemTime(new Date('2024-06-03T00:00:00Z'));
const result = dttmToDayjs('now');
// dttmToDayjs's fallback branch (`extendedDayjs(dttm)`) re-parses a naive
// "YYYY-MM-DDTHH:mm:ss" string -- the format produced when "now" gets
// resolved and formatted elsewhere in this module -- as local wall-clock
// time. For that round trip to reproduce the actual current moment,
// resolving "now" must also use local wall-clock time rather than UTC.
expect(result.format('YYYY-MM-DD HH:mm:ss')).toEqual('2024-06-02 20:00:00');
});
test('dttmToDayjs("today") resolves to local midnight, not UTC midnight', () => {
jest.useFakeTimers();
// 2am UTC on June 3rd is still June 2nd, 10pm, in America/New_York.
jest.setSystemTime(new Date('2024-06-03T02:00:00Z'));
const result = dttmToDayjs('today');
expect(result.format('YYYY-MM-DD HH:mm:ss')).toEqual('2024-06-02 00:00:00');
});

View File

@@ -40,11 +40,18 @@ export const ISO8601_AND_CONSTANT = RegExp(
const SPECIFIC_MODE = ['specific', 'today', 'now'];
export const dttmToDayjs = (dttm: string): Dayjs => {
// "now"/"today" are later formatted (see dttmToString) into a naive
// "YYYY-MM-DDTHH:mm:ss" string with no UTC offset, and that string is
// re-parsed elsewhere as local time (the `extendedDayjs(dttm)` fallback
// below). Resolving these constants in UTC rather than local time would
// make that round trip drift by the browser's UTC offset, which is what
// caused the "Now" anchor to display and query the wrong wall-clock time
// for users outside UTC.
if (dttm === 'now') {
return extendedDayjs().utc().startOf('second');
return extendedDayjs().startOf('second');
}
if (dttm === 'today') {
return extendedDayjs().utc().startOf('day');
return extendedDayjs().startOf('day');
}
return extendedDayjs(dttm);
};