From a591130e0bd3c817af9ad937f63f1af1fce90740 Mon Sep 17 00:00:00 2001 From: Ville Brofeldt <33317356+villebro@users.noreply.github.com> Date: Mon, 13 Mar 2023 14:46:39 +0200 Subject: [PATCH] fix(trino): normalize non-iso timestamps (#23339) --- .../superset-ui-core/src/time-format/index.ts | 2 + .../time-format/utils/normalizeTimestamp.ts | 28 ++++++++++++ .../utils/normalizeTimestamp.test.ts | 43 +++++++++++++++++++ .../src/utils/DateWithFormatter.ts | 21 ++++----- 4 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 superset-frontend/packages/superset-ui-core/src/time-format/utils/normalizeTimestamp.ts create mode 100644 superset-frontend/packages/superset-ui-core/test/time-format/utils/normalizeTimestamp.test.ts diff --git a/superset-frontend/packages/superset-ui-core/src/time-format/index.ts b/superset-frontend/packages/superset-ui-core/src/time-format/index.ts index 48ac1a6803db5..b086effd246a9 100644 --- a/superset-frontend/packages/superset-ui-core/src/time-format/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/time-format/index.ts @@ -36,4 +36,6 @@ export { default as smartDateFormatter } from './formatters/smartDate'; export { default as smartDateDetailedFormatter } from './formatters/smartDateDetailed'; export { default as smartDateVerboseFormatter } from './formatters/smartDateVerbose'; +export { default as normalizeTimestamp } from './utils/normalizeTimestamp'; + export * from './types'; diff --git a/superset-frontend/packages/superset-ui-core/src/time-format/utils/normalizeTimestamp.ts b/superset-frontend/packages/superset-ui-core/src/time-format/utils/normalizeTimestamp.ts new file mode 100644 index 0000000000000..0e49aee7ea754 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/time-format/utils/normalizeTimestamp.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +const TS_REGEX = /(\d{4}-\d{2}-\d{2})[\sT](\d{2}:\d{2}:\d{2}\.?\d*).*/; + +export default function normalizeTimestamp(value: string): string { + const match = value.match(TS_REGEX); + if (match) { + return `${match[1]}T${match[2]}Z`; + } + return value; +} diff --git a/superset-frontend/packages/superset-ui-core/test/time-format/utils/normalizeTimestamp.test.ts b/superset-frontend/packages/superset-ui-core/test/time-format/utils/normalizeTimestamp.test.ts new file mode 100644 index 0000000000000..6ccdcb574deb8 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/test/time-format/utils/normalizeTimestamp.test.ts @@ -0,0 +1,43 @@ +/* + * 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 normalizeTimestamp from '../../../src/time-format/utils/normalizeTimestamp'; + +test('normalizeTimestamp should normalize typical timestamps', () => { + expect(normalizeTimestamp('2023-03-11 08:26:52.695 UTC')).toEqual( + '2023-03-11T08:26:52.695Z', + ); + expect(normalizeTimestamp('2023-03-11 08:26:52.695 Europe/Helsinki')).toEqual( + '2023-03-11T08:26:52.695Z', + ); + expect(normalizeTimestamp('2023-03-11T08:26:52.695 UTC')).toEqual( + '2023-03-11T08:26:52.695Z', + ); + expect(normalizeTimestamp('2023-03-11T08:26:52.695')).toEqual( + '2023-03-11T08:26:52.695Z', + ); + expect(normalizeTimestamp('2023-03-11 08:26:52')).toEqual( + '2023-03-11T08:26:52Z', + ); +}); + +test('normalizeTimestamp should return unmatched timestamps as-is', () => { + expect(normalizeTimestamp('abcd')).toEqual('abcd'); + expect(normalizeTimestamp('03/11/2023')).toEqual('03/11/2023'); +}); diff --git a/superset-frontend/plugins/plugin-chart-table/src/utils/DateWithFormatter.ts b/superset-frontend/plugins/plugin-chart-table/src/utils/DateWithFormatter.ts index eef513bca0406..c92c2ca1abb3a 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/utils/DateWithFormatter.ts +++ b/superset-frontend/plugins/plugin-chart-table/src/utils/DateWithFormatter.ts @@ -16,9 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -import { DataRecordValue, TimeFormatFunction } from '@superset-ui/core'; - -const REGEXP_TIMESTAMP_NO_TIMEZONE = /T(\d{2}:){2}\d{2}$/; +import { + DataRecordValue, + normalizeTimestamp, + TimeFormatFunction, +} from '@superset-ui/core'; /** * Extended Date object with a custom formatter, and retains the original input @@ -31,19 +33,12 @@ export default class DateWithFormatter extends Date { constructor( input: DataRecordValue, - { - formatter = String, - forceUTC = true, - }: { formatter?: TimeFormatFunction; forceUTC?: boolean } = {}, + { formatter = String }: { formatter?: TimeFormatFunction } = {}, ) { let value = input; // assuming timestamps without a timezone is in UTC time - if ( - forceUTC && - typeof value === 'string' && - REGEXP_TIMESTAMP_NO_TIMEZONE.test(value) - ) { - value = `${value}Z`; + if (typeof value === 'string') { + value = normalizeTimestamp(value); } super(value as string);