From b068484b09ebc4a5f9dc0bad979072310b812ec1 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Thu, 13 Jan 2022 22:24:47 +0100 Subject: [PATCH] fix(xy): switch default timezone to `local` (#1544) The default timezone used when no timezone prop is provided is now aligned to the browser's local timezone. BREAKING CHANGE: The time axis labels of a time-series chart configured without the timeZone prop are now rendering the labels with the local browser timezone instead of UTC. --- integration/tests/timezone.test.ts | 20 +++++++++++++++++++ .../xy_chart/domains/x_domain.test.ts | 12 +++++------ .../chart_types/xy_chart/domains/x_domain.ts | 4 ++-- .../xy_chart/state/utils/utils.test.ts | 6 ++++-- .../xy_chart/utils/axis_utils.test.ts | 2 ++ .../src/chart_types/xy_chart/utils/specs.ts | 3 ++- packages/charts/src/mocks/xy/domains.ts | 2 +- .../charts/src/scales/scale_continuous.ts | 4 ++-- 8 files changed, 39 insertions(+), 14 deletions(-) diff --git a/integration/tests/timezone.test.ts b/integration/tests/timezone.test.ts index 762604e427..3113fb27e9 100644 --- a/integration/tests/timezone.test.ts +++ b/integration/tests/timezone.test.ts @@ -19,4 +19,24 @@ describe('Time zone', () => { 'http://localhost:9001/?path=/story/scales--timezone-configuration&globals=theme:light&knob-dataset=utc-8&knob-tooltip=utc', ); }); + // skip until puppeteer is updated to > 4.x + it.skip('use default local timezone America/New_York', async () => { + // await page.emulateTimezone('America/New_York'); + // time should start at 06:00 (UTC time is 11:00) + await common.expectChartWithMouseAtUrlToMatchScreenshot( + 'http://localhost:9001/?path=/story/bar-chart--with-time-x-axis', + { left: 80, top: 100 }, + { screenshotSelector: 'body' }, + ); + }); + // skipped until puppeteer is updated to > 4.x + it.skip('use default local timezone Europe/Rome', async () => { + // await page.emulateTimezone('Europe/Rome'); + // time should start at 12:00 (UTC time is 11:00) + await common.expectChartWithMouseAtUrlToMatchScreenshot( + 'http://localhost:9001/?path=/story/bar-chart--with-time-x-axis', + { left: 80, top: 100 }, + { screenshotSelector: 'body' }, + ); + }); }); diff --git a/packages/charts/src/chart_types/xy_chart/domains/x_domain.test.ts b/packages/charts/src/chart_types/xy_chart/domains/x_domain.test.ts index 4a5ef8c7d0..43fe00392f 100644 --- a/packages/charts/src/chart_types/xy_chart/domains/x_domain.test.ts +++ b/packages/charts/src/chart_types/xy_chart/domains/x_domain.test.ts @@ -42,7 +42,7 @@ describe('X Domain', () => { type: getXScaleTypeFromSpec(ScaleType.Linear), nice: getXNiceFromSpec(), isBandScale: true, - timeZone: 'utc', + timeZone: 'local', }); }); @@ -58,7 +58,7 @@ describe('X Domain', () => { type: getXScaleTypeFromSpec(ScaleType.Ordinal), nice: getXNiceFromSpec(), isBandScale: true, - timeZone: 'utc', + timeZone: 'local', }); }); @@ -74,7 +74,7 @@ describe('X Domain', () => { type: getXScaleTypeFromSpec(ScaleType.Linear), nice: getXNiceFromSpec(), isBandScale: false, - timeZone: 'utc', + timeZone: 'local', }); }); test('Should return correct scale type with single line (time)', () => { @@ -132,7 +132,7 @@ describe('X Domain', () => { type: getXScaleTypeFromSpec(ScaleType.Time), nice: getXNiceFromSpec(), isBandScale: false, - timeZone: 'utc', + timeZone: 'local', }); }); @@ -152,7 +152,7 @@ describe('X Domain', () => { type: getXScaleTypeFromSpec(ScaleType.Ordinal), nice: getXNiceFromSpec(), isBandScale: false, - timeZone: 'utc', + timeZone: 'local', }); }); test('Should return correct scale type with multi bar, area with different scale types (linear, ordinal)', () => { @@ -171,7 +171,7 @@ describe('X Domain', () => { type: getXScaleTypeFromSpec(ScaleType.Ordinal), nice: getXNiceFromSpec(), isBandScale: true, - timeZone: 'utc', + timeZone: 'local', }); }); test('Should return correct scale type with multi bar, area with same scale types (linear, linear)', () => { diff --git a/packages/charts/src/chart_types/xy_chart/domains/x_domain.ts b/packages/charts/src/chart_types/xy_chart/domains/x_domain.ts index 193c792860..902c1a736c 100644 --- a/packages/charts/src/chart_types/xy_chart/domains/x_domain.ts +++ b/packages/charts/src/chart_types/xy_chart/domains/x_domain.ts @@ -142,7 +142,7 @@ export function findMinInterval(xValues: number[]): number { * Convert the scale types of a set of specification to a generic one. * If there are at least one `ordinal` scale type, the resulting scale is coerced to ordinal. * If there are only `continuous` scale types, the resulting scale is coerced to linear. - * If there are only `time` scales, we coerce the timeZone to `utc` only if we have multiple + * If there are only `time` scales, we coerce the timeZone to `local` only if we have multiple * different timezones. * @returns the coerced scale type, the timezone and a parameter that describe if its a bandScale or not * @internal @@ -167,6 +167,6 @@ export function convertXScaleTypes( : ScaleType.Linear; // if Ordinal is not present, coerce to Linear, whether it's present or not const nice = !niceDomains.includes(false); const isBandScale = seriesTypes.has(SeriesType.Bar); - const timeZone = timeZones.size === 1 ? timeZones.values().next().value : 'utc'; + const timeZone = timeZones.size === 1 ? timeZones.values().next().value : 'local'; return { type, nice, isBandScale, timeZone }; } diff --git a/packages/charts/src/chart_types/xy_chart/state/utils/utils.test.ts b/packages/charts/src/chart_types/xy_chart/state/utils/utils.test.ts index fa052047bb..c05dd7b958 100644 --- a/packages/charts/src/chart_types/xy_chart/state/utils/utils.test.ts +++ b/packages/charts/src/chart_types/xy_chart/state/utils/utils.test.ts @@ -75,7 +75,8 @@ describe('Chart State utils', () => { isBandScale: false, minInterval: 1, logBase: 10, - timeZone: 'utc', + // the default timezone (local) is resolved in computeSeriesDomains fn with Intl functions + timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone, }), ); expect(domains.yDomains).toEqual([ @@ -126,7 +127,8 @@ describe('Chart State utils', () => { isBandScale: false, minInterval: 1, logBase: 10, - timeZone: 'utc', + // the default timezone (local) is resolved in computeSeriesDomains fn with Intl functions + timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone, }), ); expect(domains.yDomains).toEqual([ diff --git a/packages/charts/src/chart_types/xy_chart/utils/axis_utils.test.ts b/packages/charts/src/chart_types/xy_chart/utils/axis_utils.test.ts index 695869eed1..7f6bd7846d 100644 --- a/packages/charts/src/chart_types/xy_chart/utils/axis_utils.test.ts +++ b/packages/charts/src/chart_types/xy_chart/utils/axis_utils.test.ts @@ -1421,6 +1421,7 @@ describe('Axis computational utils', () => { isBandScale: false, domain: [1547190000000, 1547622000000], minInterval: 86400000, + timeZone: 'utc', }); const scale: Scale = computeXScale({ xDomain: xDomainTime, @@ -1575,6 +1576,7 @@ describe('Axis computational utils', () => { isBandScale: false, domain: [1547190000000, 1547622000000], minInterval: 86400000, + timeZone: 'utc', }); const scale = computeXScale({ xDomain: xDomainTime, totalBarsInCluster: 0, range: [0, 603.5] }); const offset = 0; diff --git a/packages/charts/src/chart_types/xy_chart/utils/specs.ts b/packages/charts/src/chart_types/xy_chart/utils/specs.ts index 046a6ed09e..b43dc00ae8 100644 --- a/packages/charts/src/chart_types/xy_chart/utils/specs.ts +++ b/packages/charts/src/chart_types/xy_chart/utils/specs.ts @@ -521,6 +521,7 @@ export interface SeriesScales { * compute a nice set of xScale ticks. Can be any IANA zone supported by * the host environment, or a fixed-offset name of the form 'utc+3', * or the strings 'local' or 'utc'. + * @defaultValue `local` */ timeZone?: string; /** @@ -710,7 +711,7 @@ export interface AxisSpec extends Spec { groupId: GroupId; /** Hide this axis */ hide: boolean; - /** shows all ticks and gridlines, including those belonging to labels that got culled due to overlapping with other labels*/ + /** shows all ticks and gridlines, including those belonging to labels that got culled due to overlapping with other labels */ showOverlappingTicks: boolean; /** Shows all labels, also the overlapping ones */ showOverlappingLabels: boolean; diff --git a/packages/charts/src/mocks/xy/domains.ts b/packages/charts/src/mocks/xy/domains.ts index 95232a1b32..2d7ac6b59d 100644 --- a/packages/charts/src/mocks/xy/domains.ts +++ b/packages/charts/src/mocks/xy/domains.ts @@ -25,7 +25,7 @@ export class MockXDomain { ...X_SCALE_DEFAULT, isBandScale: X_SCALE_DEFAULT.type !== ScaleType.Ordinal, minInterval: 0, - timeZone: 'UTC', + timeZone: 'local', domain: [0, 1], }; diff --git a/packages/charts/src/scales/scale_continuous.ts b/packages/charts/src/scales/scale_continuous.ts index 5017ebdcec..7a3ee29043 100644 --- a/packages/charts/src/scales/scale_continuous.ts +++ b/packages/charts/src/scales/scale_continuous.ts @@ -39,7 +39,7 @@ const SCALES = { const defaultScaleOptions: ScaleOptions = { bandwidth: 0, minInterval: 0, - timeZone: 'utc', + timeZone: 'local', totalBarsInCluster: 1, barsPadding: 0, constrainDomainPadding: true, @@ -349,7 +349,7 @@ type ScaleOptions = Required & { /** * A time zone identifier. Can be any IANA zone supported by he host environment, * or a fixed-offset name of the form 'utc+3', or the strings 'local' or 'utc'. - * @defaultValue `utc` + * @defaultValue `local` */ timeZone: string; /**