diff --git a/packages/grafana-data/src/datetime/datemath.test.ts b/packages/grafana-data/src/datetime/datemath.test.ts index d644f3be4a1..cc857c9311f 100644 --- a/packages/grafana-data/src/datetime/datemath.test.ts +++ b/packages/grafana-data/src/datetime/datemath.test.ts @@ -54,6 +54,53 @@ describe('DateMath', () => { expect(startOfDay).toBe(expected.getTime()); }); + describe('with fiscal quarters', () => { + beforeEach(() => { + const fixedTime = dateTime('2023-07-05T06:06:06.666Z').valueOf(); + clock = sinon.useFakeTimers(fixedTime); + }); + + afterEach(() => { + clock.restore(); + }); + + it('should parse current fiscal quarter correctly', () => { + const today = new Date(); + const expected = new Date(Date.UTC(today.getUTCFullYear(), 6, 1, 0, 0, 0, 0)); + + const startOfDay = dateMath.parse('now/fQ', false, 'utc', 0)!.valueOf(); + expect(startOfDay).toBe(expected.getTime()); + }); + + it('should parse previous fiscal quarter correctly', () => { + const today = new Date(); + const expected = new Date(Date.UTC(today.getUTCFullYear(), 3, 1, 0, 0, 0, 0)); + + const startOfDay = dateMath.parse('now-1Q/fQ', false, 'utc', 0)!.valueOf(); + expect(startOfDay).toBe(expected.getTime()); + }); + + describe('with a custom fiscal year start month', () => { + const FISCAL_YEAR_START_MONTH = 7; // August + + it('should parse current fiscal quarter correctly', () => { + const today = new Date(); + const expected = new Date(Date.UTC(today.getUTCFullYear(), 4, 1, 0, 0, 0, 0)); + + const startOfDay = dateMath.parse('now/fQ', false, 'utc', FISCAL_YEAR_START_MONTH)!.valueOf(); + expect(startOfDay).toBe(expected.getTime()); + }); + + it('should parse previous fiscal quarter correctly', () => { + const today = new Date(); + const expected = new Date(Date.UTC(today.getUTCFullYear(), 1, 1, 0, 0, 0, 0)); + + const startOfDay = dateMath.parse('now-1Q/fQ', false, 'utc', FISCAL_YEAR_START_MONTH)!.valueOf(); + expect(startOfDay).toBe(expected.getTime()); + }); + }); + }); + describe('subtraction', () => { let now: DateTime; let anchored: DateTime; @@ -175,8 +222,8 @@ describe('DateMath', () => { //fq1 = 2021-02-01 - 2021-04-30 //fq2 = 2021-05-01 - 2021-07-31 - //fq4 = 2021-08-01 - 2021-10-31 - //fq5 = 2021-11-01 - 2022-01-31 + //fq3 = 2021-08-01 - 2021-10-31 + //fq4 = 2021-11-01 - 2022-01-31 it('Should round to start of q2 when one month into q2', () => { let date = dateMath.roundToFiscal(1, dateTime([2021, 6, 1]), 'Q', false); @@ -201,5 +248,15 @@ describe('DateMath', () => { let expected = dateTime([2022, 0, 31]).endOf('M'); expect(date!.valueOf()).toEqual(expected.valueOf()); }); + + it('should handle fyStartMonths set later in the year correctly', () => { + // Use fyStartMonth to 10 (November) + // Fiscal quarters are then Nov-Jan, Feb-Apr, May-Jul, Aug-Oct + // Use 1st Jan as the date to round + let date = dateMath.roundToFiscal(10, dateTime([2022, 0, 1]), 'Q', false); + // This should round back to 1st Nov 2021 + let expected = dateTime([2021, 10, 1]); + expect(date!.valueOf()).toEqual(expected.valueOf()); + }); }); }); diff --git a/packages/grafana-data/src/datetime/datemath.ts b/packages/grafana-data/src/datetime/datemath.ts index 5478aa53edf..becb82991b2 100644 --- a/packages/grafana-data/src/datetime/datemath.ts +++ b/packages/grafana-data/src/datetime/datemath.ts @@ -163,15 +163,11 @@ export function parseDateMath( return undefined; } else { if (type === 0) { - if (roundUp) { - if (isFiscal) { - roundToFiscal(fiscalYearStartMonth, dateTime, unit, roundUp); - } else { - dateTime.endOf(unit); - } + if (isFiscal) { + roundToFiscal(fiscalYearStartMonth, dateTime, unit, roundUp); } else { - if (isFiscal) { - roundToFiscal(fiscalYearStartMonth, dateTime, unit, roundUp); + if (roundUp) { + dateTime.endOf(unit); } else { dateTime.startOf(unit); } @@ -199,7 +195,8 @@ export function roundToFiscal(fyStartMonth: number, dateTime: any, unit: string, if (roundUp) { roundToFiscal(fyStartMonth, dateTime, unit, false).add(2, 'M').endOf('M'); } else { - dateTime.subtract((dateTime.month() - fyStartMonth + 3) % 3, 'M').startOf('M'); + // why + 12? to ensure this number is always a positive offset from fyStartMonth + dateTime.subtract((dateTime.month() - fyStartMonth + 12) % 3, 'M').startOf('M'); } return dateTime; default: