Skip to content
Snippets Groups Projects
Unverified Commit 8e17e13e authored by Emmad Usmani's avatar Emmad Usmani Committed by GitHub
Browse files

fix percent change across daylight savings (#42482)

* fix percent change across DST

* add e2e tests
parent 6d655546
No related branches found
No related tags found
No related merge requests found
......@@ -593,6 +593,107 @@ describe("scenarios > visualizations > line/bar chart > tooltips", () => {
testTooltipExcludesText("Compared to preivous month");
});
});
describe("> percent change across daylight savings time change", () => {
const SUM_OF_TOTAL_APRIL = {
name: "Q1",
query: {
"source-table": ORDERS_ID,
aggregation: [["sum", ["field", ORDERS.TOTAL, null]]],
breakout: [["field", ORDERS.CREATED_AT, { "temporal-unit": "month" }]],
filter: [
"between",
["field", 39, { "base-type": "type/DateTime" }],
"2024-01-01",
"2024-05-30",
],
},
display: "line",
};
const APRIL_CHANGES = [null, "-10.89%", "11.1%", "-2.89%"];
const SUM_OF_TOTAL_DST_WEEK = {
name: "Q1",
query: {
"source-table": ORDERS_ID,
aggregation: [["sum", ["field", ORDERS.TOTAL, null]]],
breakout: [["field", ORDERS.CREATED_AT, { "temporal-unit": "week" }]],
filter: [
"between",
["field", 39, { "base-type": "type/DateTime" }],
"2024-03-01",
"2024-03-31",
],
},
display: "line",
};
const DST_WEEK_CHANGES = [null, "191.48%", "4.76%", "-2.36%"];
const SUM_OF_TOTAL_DST_DAY = {
name: "Q1",
query: {
"source-table": ORDERS_ID,
aggregation: [["sum", ["field", ORDERS.TOTAL, null]]],
breakout: [["field", ORDERS.CREATED_AT, { "temporal-unit": "day" }]],
filter: [
"between",
["field", 39, { "base-type": "type/DateTime" }],
"2024-03-09",
"2024-03-12",
],
},
display: "line",
};
const DST_DAY_CHANGES = [null, "27.5%", "-26.16%"];
it("should not omit percent change on April", () => {
setup({ question: SUM_OF_TOTAL_APRIL }).then(dashboardId => {
visitDashboard(dashboardId);
});
APRIL_CHANGES.forEach(change => {
showTooltipForCircleInSeries("#88BF4D");
if (change === null) {
testTooltipExcludesText("Compared to preivous");
return;
}
testPairedTooltipValues("Compared to previous month", change);
});
});
it("should not omit percent change the week after DST begins", () => {
setup({ question: SUM_OF_TOTAL_DST_WEEK }).then(dashboardId => {
visitDashboard(dashboardId);
});
DST_WEEK_CHANGES.forEach(change => {
showTooltipForCircleInSeries("#88BF4D");
if (change === null) {
testTooltipExcludesText("Compared to preivous");
return;
}
testPairedTooltipValues("Compared to previous week", change);
});
});
it("should not omit percent change the day after DST begins", () => {
setup({ question: SUM_OF_TOTAL_DST_DAY }).then(dashboardId => {
visitDashboard(dashboardId);
});
DST_DAY_CHANGES.forEach(change => {
showTooltipForCircleInSeries("#88BF4D");
if (change === null) {
testTooltipExcludesText("Compared to preivous");
return;
}
testPairedTooltipValues("Compared to previous day", change);
});
});
});
});
function setup({ question, addedSeriesQuestion }) {
......
......@@ -3,6 +3,31 @@ import dayjs from "dayjs";
import type { DatetimeUnit } from "metabase-types/api/query";
const DAYLIGHT_SAVINGS_CHANGE_TOLERANCE: Record<string, number> = {
minute: 0,
hour: 0,
// It's not possible to have two consecutive hours or minutes across the
// daylight savings time change. Daylight savings begins at 2AM on March 10th,
// so after 1AM, the next hour is 3AM.
day: 0.05,
week: 0.01,
month: 0.01,
quarter: 0,
year: 0,
};
/**
* This function is used to get a tolerance for the difference between two dates
* across the daylight savings time change, using dayjs' date.diff method. For
* example between March 10th (when daylight savings beigns) and March 11th, the
* .diff method will return
*/
export function getDaylightSavingsChangeTolerance(unit: string) {
return unit in DAYLIGHT_SAVINGS_CHANGE_TOLERANCE
? DAYLIGHT_SAVINGS_CHANGE_TOLERANCE[unit]
: 0;
}
const TEXT_UNIT_FORMATS = {
"day-of-week": (value: string) => {
const day = dayjs.tz(value, "ddd").startOf("day");
......
......@@ -3,7 +3,10 @@ import _ from "underscore";
import { NULL_DISPLAY_VALUE } from "metabase/lib/constants";
import { formatChangeWithSign } from "metabase/lib/formatting";
import { getObjectKeys } from "metabase/lib/objects";
import { parseTimestamp } from "metabase/lib/time-dayjs";
import {
getDaylightSavingsChangeTolerance,
parseTimestamp,
} from "metabase/lib/time-dayjs";
import { checkNumber, isNotNull } from "metabase/lib/types";
import {
ORIGINAL_INDEX_DATA_KEY,
......@@ -217,9 +220,15 @@ const getTooltipFooterData = (
? "quarter"
: chartModel.xAxisModel.interval.unit;
const dateDifference = currentDate.diff(
previousDate,
chartModel.xAxisModel.interval.unit,
true,
);
let isOneIntervalAgo =
currentDate.diff(previousDate, chartModel.xAxisModel.interval.unit) ===
chartModel.xAxisModel.interval.count;
Math.abs(dateDifference - chartModel.xAxisModel.interval.count) <=
getDaylightSavingsChangeTolerance(chartModel.xAxisModel.interval.unit);
// Comparing the 2nd and 1st quarter of the year needs to be checked
// specially, because there are fewer days in this period due to Feburary
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment