Skip to content

Commit

Permalink
[IMP] pivot: support iso_week_number granularity
Browse files Browse the repository at this point in the history
closes #4228

Task: 3932401
Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
  • Loading branch information
pro-odoo committed May 23, 2024
1 parent f5a8c01 commit bad4e1d
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 1 deletion.
8 changes: 8 additions & 0 deletions src/helpers/dates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ export class DateTime {
return this.jsDate.getUTCSeconds();
}

getIsoWeek() {
const date = new Date(this.jsDate.getTime());
const dayNumber = date.getUTCDay() || 7;
date.setUTCDate(date.getUTCDate() + 4 - dayNumber);
const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
return Math.ceil(((date.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
}

setFullYear(year: number) {
return this.jsDate.setUTCFullYear(year);
}
Expand Down
9 changes: 8 additions & 1 deletion src/helpers/pivot/pivot_registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,14 @@ pivotRegistry.add("SPREADSHEET", {
definition: SpreadsheetPivotRuntimeDefinition,
externalData: false,
onIterationEndEvaluation: (pivot: SpreadsheetPivot) => pivot.markAsDirtyForEvaluation(),
granularities: ["year_number", "quarter_number", "month_number", "day_of_month", "day"],
granularities: [
"year_number",
"quarter_number",
"month_number",
"iso_week_number",
"day_of_month",
"day",
],
isMeasureCandidate: (field: PivotField) => !["date", "boolean"].includes(field.type),
isGroupable: () => true,
});
11 changes: 11 additions & 0 deletions src/helpers/pivot/spreadsheet_pivot/date_spreadsheet_pivot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export function createDate(dimension: PivotDimension, value: FieldValue["value"]
case "month_number":
number = date.getMonth();
break;
case "iso_week_number":
number = date.getIsoWeek();
break;
case "day_of_month":
number = date.getDate();
break;
Expand Down Expand Up @@ -50,6 +53,10 @@ export function createDate(dimension: PivotDimension, value: FieldValue["value"]
* set: { 43_831 },
* values: { '43_831': 0 }
* },
* iso_week_number: {
* set: { 43_831 },
* values: { '43_831': 1 }
* },
* day_of_month: {
* set: { 43_831 },
* values: { '43_831': 1 }
Expand All @@ -76,6 +83,10 @@ const MAP_VALUE_DIMENSION_DATE: Record<
set: new Set<FieldValue["value"]>(),
values: {},
},
iso_week_number: {
set: new Set<FieldValue["value"]>(),
values: {},
},
day_of_month: {
set: new Set<FieldValue["value"]>(),
values: {},
Expand Down
24 changes: 24 additions & 0 deletions tests/functions/dates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1012,3 +1012,27 @@ describe("Number of digits in year/month/days in format", () => {
expect(parseDateTime("1-3-2002", locale)).toMatchObject({ format: "m-d-yyyy" });
});
});

describe("Datetime", () => {
test("isoWeekNumber", () => {
expect(parseDateTime("2020/01/01", locale)?.jsDate?.getIsoWeek()).toBe(1);
// Week 53 in 2020. The first Thursday in 2021 is on the 7th of January.
// So, 1st to 3rd of January are in week 53 of 2020 (Friday, Saturday and Sunday).
expect(parseDateTime("2021/01/01", locale)?.jsDate?.getIsoWeek()).toBe(53);
expect(parseDateTime("2021/01/02", locale)?.jsDate?.getIsoWeek()).toBe(53);
expect(parseDateTime("2021/01/03", locale)?.jsDate?.getIsoWeek()).toBe(53);
expect(parseDateTime("2021/01/04", locale)?.jsDate?.getIsoWeek()).toBe(1);
expect(parseDateTime("2021/01/05", locale)?.jsDate?.getIsoWeek()).toBe(1);
expect(parseDateTime("2021/01/06", locale)?.jsDate?.getIsoWeek()).toBe(1);
expect(parseDateTime("2021/01/07", locale)?.jsDate?.getIsoWeek()).toBe(1);
expect(parseDateTime("2021/03/10", locale)?.jsDate?.getIsoWeek()).toBe(10);
expect(parseDateTime("2021/05/16", locale)?.jsDate?.getIsoWeek()).toBe(19);
expect(parseDateTime("2021/05/17", locale)?.jsDate?.getIsoWeek()).toBe(20);

expect(parseDateTime("2024/01/01", locale)?.jsDate?.getIsoWeek()).toBe(1);
expect(parseDateTime("2024/02/29", locale)?.jsDate?.getIsoWeek()).toBe(9);
expect(parseDateTime("2024/12/29", locale)?.jsDate?.getIsoWeek()).toBe(52);
// 2nd of January 2025 is the first thursday of the year, so week 1 starts on the 30th of December 2024
expect(parseDateTime("2024/12/30", locale)?.jsDate?.getIsoWeek()).toBe(1);
});
});
5 changes: 5 additions & 0 deletions tests/pivots/spreadsheet_pivot/date_spreadsheet_pivot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function createPivotDimension(granularity: string): PivotDimension {
const YEAR_NUMBER_DIMENSION = createPivotDimension("year_number");
const QUARTER_NUMBER_DIMENSION = createPivotDimension("quarter_number");
const MONTH_NUMBER_DIMENSION = createPivotDimension("month_number");
const ISO_WEEK_NUMBER_DIMENSION = createPivotDimension("iso_week_number");
const DAY_OF_MONTH_DIMENSION = createPivotDimension("day_of_month");
const DAY_DIMENSION = createPivotDimension("day");

Expand All @@ -26,20 +27,23 @@ describe("Date Spreadsheet Pivot", () => {
expect(createDate(YEAR_NUMBER_DIMENSION, d05_april_2024, DEFAULT_LOCALE)).toBe(2024);
expect(createDate(QUARTER_NUMBER_DIMENSION, d05_april_2024, DEFAULT_LOCALE)).toBe(2);
expect(createDate(MONTH_NUMBER_DIMENSION, d05_april_2024, DEFAULT_LOCALE)).toBe(3);
expect(createDate(ISO_WEEK_NUMBER_DIMENSION, d05_april_2024, DEFAULT_LOCALE)).toBe(14);
expect(createDate(DAY_OF_MONTH_DIMENSION, d05_april_2024, DEFAULT_LOCALE)).toBe(5);
expect(createDate(DAY_DIMENSION, d05_april_2024, DEFAULT_LOCALE)).toBe(d05_april_2024);

const d04_may_2024 = 45_416;
expect(createDate(YEAR_NUMBER_DIMENSION, d04_may_2024, DEFAULT_LOCALE)).toBe(2024);
expect(createDate(QUARTER_NUMBER_DIMENSION, d04_may_2024, DEFAULT_LOCALE)).toBe(2);
expect(createDate(MONTH_NUMBER_DIMENSION, d04_may_2024, DEFAULT_LOCALE)).toBe(4);
expect(createDate(ISO_WEEK_NUMBER_DIMENSION, d04_may_2024, DEFAULT_LOCALE)).toBe(18);
expect(createDate(DAY_OF_MONTH_DIMENSION, d04_may_2024, DEFAULT_LOCALE)).toBe(4);
expect(createDate(DAY_DIMENSION, d04_may_2024, DEFAULT_LOCALE)).toBe(d04_may_2024);

const d01_january_2019 = 43_466;
expect(createDate(YEAR_NUMBER_DIMENSION, d01_january_2019, DEFAULT_LOCALE)).toBe(2019);
expect(createDate(QUARTER_NUMBER_DIMENSION, d01_january_2019, DEFAULT_LOCALE)).toBe(1);
expect(createDate(MONTH_NUMBER_DIMENSION, d01_january_2019, DEFAULT_LOCALE)).toBe(0);
expect(createDate(ISO_WEEK_NUMBER_DIMENSION, d01_january_2019, DEFAULT_LOCALE)).toBe(1);
expect(createDate(DAY_OF_MONTH_DIMENSION, d01_january_2019, DEFAULT_LOCALE)).toBe(1);
expect(createDate(DAY_DIMENSION, d01_january_2019, DEFAULT_LOCALE)).toBe(d01_january_2019);
});
Expand All @@ -50,6 +54,7 @@ describe("Date Spreadsheet Pivot", () => {
expect(createDate(YEAR_NUMBER_DIMENSION, d05_april_2024_15h, DEFAULT_LOCALE)).toBe(2024);
expect(createDate(QUARTER_NUMBER_DIMENSION, d05_april_2024_15h, DEFAULT_LOCALE)).toBe(2);
expect(createDate(MONTH_NUMBER_DIMENSION, d05_april_2024_15h, DEFAULT_LOCALE)).toBe(3);
expect(createDate(ISO_WEEK_NUMBER_DIMENSION, d05_april_2024_15h, DEFAULT_LOCALE)).toBe(14);
expect(createDate(DAY_OF_MONTH_DIMENSION, d05_april_2024_15h, DEFAULT_LOCALE)).toBe(5);
expect(createDate(DAY_DIMENSION, d05_april_2024_15h, DEFAULT_LOCALE)).toBe(
Math.floor(d05_april_2024_15h)
Expand Down
11 changes: 11 additions & 0 deletions tests/pivots/spreadsheet_pivot/spreadsheet_pivot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,17 @@ describe("Spreadsheet Pivot", () => {
expect(getEvaluatedGrid(model, "B26:E26")).toEqual([["1", "2", "Total", ""]]);
});

test("iso_week_number should be supported", () => {
const model = createModelWithPivot("A1:I5");
updatePivot(model, "1", {
columns: [{ name: "Created on", granularity: "iso_week_number", order: "asc" }],
rows: [],
measures: [{ name: "Expected Revenue", aggregator: "sum" }],
});
setCellContent(model, "A26", `=pivot(1)`);
expect(getEvaluatedGrid(model, "B26:F26")).toEqual([["5", "9", "14", "Total", ""]]);
});

describe("Pivot reevaluation", () => {
test("Pivot fields reevaluation", () => {
const model = new Model({
Expand Down

0 comments on commit bad4e1d

Please sign in to comment.