diff --git a/packages/grafana-data/src/datetime/datemath.ts b/packages/grafana-data/src/datetime/datemath.ts index 2fe08513f52..ebfc079f755 100644 --- a/packages/grafana-data/src/datetime/datemath.ts +++ b/packages/grafana-data/src/datetime/datemath.ts @@ -43,9 +43,11 @@ export function parse( if (isDateTime(text)) { return text; } + if (isDate(text)) { return dateTime(text); } + // We got some non string which is not a moment nor Date. TS should be able to check for that but not always. return undefined; } else { diff --git a/public/app/features/dashboard/services/TimeSrv.test.ts b/public/app/features/dashboard/services/TimeSrv.test.ts index e604828080e..5418d88994f 100644 --- a/public/app/features/dashboard/services/TimeSrv.test.ts +++ b/public/app/features/dashboard/services/TimeSrv.test.ts @@ -231,6 +231,24 @@ describe('timeSrv', () => { expect(time.raw.from).toBe('now'); expect(time.raw.to).toBe('now-1h'); }); + + it('should correctly handle timezones', () => { + locationService.push('/d/id?from=1718797457286&to=1718819057286'); + _dashboard = { + time: { from: '1718797457286', to: '1718819057286' }, + getTimezone: jest.fn(() => 'Africa/Cairo'), + refresh: '', + timeRangeUpdated: jest.fn(() => {}), + timepicker: {}, + }; + + timeSrv = new TimeSrv(new ContextSrvStub()); + timeSrv.init(_dashboard); + + const time = timeSrv.timeRange(); + expect(time.from.toString()).toBe('Wed Jun 19 2024 14:44:17 GMT+0300'); + expect(time.to.toString()).toBe('Wed Jun 19 2024 20:44:17 GMT+0300'); + }); }); }); diff --git a/public/app/features/dashboard/services/TimeSrv.ts b/public/app/features/dashboard/services/TimeSrv.ts index 297757650bb..7761ed37fbc 100644 --- a/public/app/features/dashboard/services/TimeSrv.ts +++ b/public/app/features/dashboard/services/TimeSrv.ts @@ -11,6 +11,7 @@ import { toUtc, IntervalValues, AppEvents, + dateTimeForTimeZone, } from '@grafana/data'; import { locationService } from '@grafana/runtime'; import { sceneGraph } from '@grafana/scenes'; @@ -106,7 +107,7 @@ export class TimeSrv { } } - private parseUrlParam(value: string) { + private parseUrlParam(value: string, timeZone?: string) { if (value.indexOf('now') !== -1) { return value; } @@ -124,7 +125,7 @@ export class TimeSrv { if (!isNaN(Number(value))) { const epoch = parseInt(value, 10); - return toUtc(epoch); + return timeZone ? dateTimeForTimeZone(timeZone, epoch) : toUtc(epoch); } return null; @@ -158,12 +159,13 @@ export class TimeSrv { this.time = this.getTimeWindow(params.get('time')!, params.get('time.window')!); } + const timeZone = this.timeModel?.getTimezone(); if (params.get('from')) { - this.time.from = this.parseUrlParam(params.get('from')!) || this.time.from; + this.time.from = this.parseUrlParam(params.get('from')!, timeZone) || this.time.from; } if (params.get('to')) { - this.time.to = this.parseUrlParam(params.get('to')!) || this.time.to; + this.time.to = this.parseUrlParam(params.get('to')!, timeZone) || this.time.to; } // if absolute ignore refresh option saved to timeModel