Skip to content

Commit

Permalink
fix(legacy-plugin-chart-calendar): fix timestamp timezone in Calendar (
Browse files Browse the repository at this point in the history
…#17664)

* fix(legacy-plugin-chart-calendar): fix timestamp timezone in Calendar

* Fix prop type
  • Loading branch information
kgabryje authored Dec 7, 2021
1 parent 2ae83fa commit e660ea2
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,10 @@
import PropTypes from 'prop-types';
import { extent as d3Extent, range as d3Range } from 'd3-array';
import { select as d3Select } from 'd3-selection';
import {
getNumberFormatter,
getTimeFormatter,
getSequentialSchemeRegistry,
} from '@superset-ui/core';
import { getSequentialSchemeRegistry } from '@superset-ui/core';
import CalHeatMap from './vendor/cal-heatmap';
import './vendor/cal-heatmap.css';

function convertUTC(dttm) {
return new Date(
dttm.getUTCFullYear(),
dttm.getUTCMonth(),
dttm.getUTCDate(),
dttm.getUTCHours(),
dttm.getUTCMinutes(),
dttm.getUTCSeconds(),
);
}

const convertUTCTS = uts => convertUTC(new Date(uts)).getTime();

const propTypes = {
data: PropTypes.shape({
// Object hashed by metric name,
Expand All @@ -65,8 +48,8 @@ const propTypes = {
showMetricName: PropTypes.bool,
showValues: PropTypes.bool,
steps: PropTypes.number,
timeFormat: PropTypes.string,
valueFormat: PropTypes.string,
timeFormatter: PropTypes.func,
valueFormatter: PropTypes.func,
verboseMap: PropTypes.object,
};

Expand All @@ -84,14 +67,11 @@ function Calendar(element, props) {
showValues,
steps,
subdomainGranularity,
timeFormat,
valueFormat,
timeFormatter,
valueFormatter,
verboseMap,
} = props;

const valueFormatter = getNumberFormatter(valueFormat);
const timeFormatter = getTimeFormatter(timeFormat);

const container = d3Select(element)
.classed('superset-legacy-chart-calendar', true)
.style('height', height);
Expand All @@ -102,17 +82,7 @@ function Calendar(element, props) {
? (date, value) => valueFormatter(value)
: null;

// Trick to convert all timestamps to UTC
// TODO: Verify if this conversion is really necessary
// since all timestamps should always be in UTC.
const metricsData = {};
Object.keys(data.data).forEach(metric => {
metricsData[metric] = {};
Object.keys(data.data[metric]).forEach(ts => {
metricsData[metric][convertUTCTS(ts * 1000) / 1000] =
data.data[metric][ts];
});
});
const metricsData = data.data;

Object.keys(metricsData).forEach(metric => {
const calContainer = div.append('div');
Expand All @@ -131,7 +101,7 @@ function Calendar(element, props) {

const cal = new CalHeatMap();
cal.init({
start: convertUTCTS(data.start),
start: data.start,
data: timestamps,
itemSelector: calContainer.node(),
legendVerticalPosition: 'top',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/

import { getNumberFormatter } from '@superset-ui/core';
import { getFormattedUTCTime } from './utils';

export default function transformProps(chartProps) {
const { height, formData, queriesData, datasource } = chartProps;
const {
Expand All @@ -34,6 +38,8 @@ export default function transformProps(chartProps) {
} = formData;

const { verboseMap } = datasource;
const timeFormatter = ts => getFormattedUTCTime(ts, xAxisTimeFormat);
const valueFormatter = getNumberFormatter(yAxisFormat);

return {
height,
Expand All @@ -48,8 +54,8 @@ export default function transformProps(chartProps) {
showValues,
steps,
subdomainGranularity,
timeFormat: xAxisTimeFormat,
valueFormat: yAxisFormat,
timeFormatter,
valueFormatter,
verboseMap,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* 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 { getTimeFormatter } from '@superset-ui/core';

// Assume that given timestamp is UTC
export const getFormattedUTCTime = (
ts: number | string,
timeFormat?: string,
) => {
const date = new Date(ts);
const offset = date.getTimezoneOffset() * 60 * 1000;
return getTimeFormatter(timeFormat)(date.getTime() - offset);
};
Original file line number Diff line number Diff line change
@@ -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.
*/

import { getFormattedUTCTime } from '../src/utils';

describe('getFormattedUTCTime', () => {
it('formatted date string should equal to UTC date', () => {
const ts = 1420070400000; // 2015.01.01 00:00:00 UTC
const formattedTime = getFormattedUTCTime(ts, '%Y-%m-%d %H:%M:%S');
expect(formattedTime).toEqual('2015-01-01 00:00:00');
});
});

0 comments on commit e660ea2

Please sign in to comment.