diff --git a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js index 037361854675c..02a93198d340c 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js +++ b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js @@ -4475,12 +4475,15 @@ export class BaseQuery { } parseCronSyntax(every) { - // One of the years that start from monday (first day of week) - // Mon, 01 Jan 2018 00:00:00 GMT - const startDate = 1514764800000; + // Use the Unix epoch as the reference point for calculating dayOffset. + // The refresh key SQL formula is: FLOOR((unix_timestamp - dayOffset) / interval) + // Since Unix timestamps are measured from Thu, 01 Jan 1970 00:00:00 UTC, + // week boundaries naturally fall on Thursdays when dividing by 604800 (1 week). + // By calculating dayOffset from the epoch to the first cron fire time, + // we correctly shift the boundaries to align with the desired day of week. const opt = { utc: true, - currentDate: new Date(startDate) + currentDate: new Date(0) // Unix epoch }; try { @@ -4488,14 +4491,15 @@ export class BaseQuery { let dayOffset = interval.next().getTime(); const dayOffsetPrev = interval.prev().getTime(); - if (dayOffsetPrev === startDate) { - dayOffset = startDate; + // If the cron fires exactly at the epoch, use 0 as dayOffset + if (dayOffsetPrev === 0) { + dayOffset = 0; } return { start: interval.next(), end: interval.next(), - dayOffset: (dayOffset - startDate) / 1000, + dayOffset: dayOffset / 1000, // Convert from ms to seconds }; } catch (err) { throw new UserError(`Invalid cron string '${every}' in refreshKey (${err})`); diff --git a/packages/cubejs-schema-compiler/test/unit/base-query.test.ts b/packages/cubejs-schema-compiler/test/unit/base-query.test.ts index 26bf4782b1558..b7e48f390cd90 100644 --- a/packages/cubejs-schema-compiler/test/unit/base-query.test.ts +++ b/packages/cubejs-schema-compiler/test/unit/base-query.test.ts @@ -1250,7 +1250,7 @@ describe('SQL Generation', () => { .toEqual([`FLOOR((${utcOffset} + EXTRACT(EPOCH FROM NOW()) - 1800) / 3600)`, false, expect.any(BaseQuery)]); expect(query.everyRefreshKeySql({ every: '30 5 * * 5', timezone })) - .toEqual([`FLOOR((${utcOffset} + EXTRACT(EPOCH FROM NOW()) - 365400) / 604800)`, false, expect.any(BaseQuery)]); + .toEqual([`FLOOR((${utcOffset} + EXTRACT(EPOCH FROM NOW()) - 106200) / 604800)`, false, expect.any(BaseQuery)]); for (let i = 1; i < 59; i++) { expect(query.everyRefreshKeySql({ every: `${i} * * * *`, timezone }))