Skip to content

Commit d412472

Browse files
committed
fix(schema-compiler): use query timezone for time granularity origin
1 parent 8e815c2 commit d412472

File tree

2 files changed

+19
-6
lines changed

2 files changed

+19
-6
lines changed

packages/cubejs-schema-compiler/src/adapter/BaseQuery.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2780,7 +2780,7 @@ export class BaseQuery {
27802780
* intervals relative to origin timestamp point
27812781
* @param {string} interval (a value expression of type interval)
27822782
* @param {string} source (a value expression of type timestamp/date)
2783-
* @param {string} origin (a value expression of type timestamp/date)
2783+
* @param {string} origin (a value expression of type timestamp/date without timezone)
27842784
* @returns {string}
27852785
*/
27862786
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -2838,7 +2838,7 @@ export class BaseQuery {
28382838
return this.timeGroupedColumn(granularity.granularityFromInterval(), dimension);
28392839
}
28402840

2841-
return this.dateBin(granularity.granularityInterval, dimension, granularity.originFormatted());
2841+
return this.dateBin(granularity.granularityInterval, dimension, granularity.originLocalFormatted());
28422842
}
28432843

28442844
/**

packages/cubejs-schema-compiler/src/adapter/Granularity.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export class Granularity {
2525
) {
2626
this.granularity = timeDimension.granularity;
2727
this.predefinedGranularity = isPredefinedGranularity(this.granularity);
28-
this.origin = moment.tz('UTC').startOf('year'); // Defaults to current year start
28+
this.origin = moment.tz(query.timezone).startOf('year'); // Defaults to current year start
2929

3030
if (this.predefinedGranularity) {
3131
this.granularityInterval = `1 ${this.granularity}`;
@@ -43,7 +43,7 @@ export class Granularity {
4343
this.granularityInterval = customGranularity.interval;
4444

4545
if (customGranularity.origin) {
46-
this.origin = moment.tz(customGranularity.origin, 'UTC');
46+
this.origin = moment.tz(customGranularity.origin, query.timezone);
4747
} else if (customGranularity.offset) {
4848
this.granularityOffset = customGranularity.offset;
4949
this.origin = addInterval(this.origin, parseSqlInterval(customGranularity.offset));
@@ -55,10 +55,20 @@ export class Granularity {
5555
return this.predefinedGranularity;
5656
}
5757

58-
public originFormatted(): string {
58+
/**
59+
* @returns origin date string in Query timezone
60+
*/
61+
public originLocalFormatted(): string {
5962
return this.origin.format('YYYY-MM-DDTHH:mm:ss.SSS');
6063
}
6164

65+
/**
66+
* @returns origin date string in UTC timezone
67+
*/
68+
public originUtcFormatted(): string {
69+
return this.origin.clone().utc().format('YYYY-MM-DDTHH:mm:ss.SSSZ');
70+
}
71+
6272
public minGranularity(): string {
6373
if (this.predefinedGranularity) {
6474
return this.granularity;
@@ -86,7 +96,10 @@ export class Granularity {
8696
return timeSeries(this.granularity, dateRange, options);
8797
}
8898

89-
return timeSeriesFromCustomInterval(this.granularityInterval, dateRange, this.origin, options);
99+
// Interval range doesn't take timezone into account and operate in kinda local timezone,
100+
// but origin is treated as a timestamp in query timezone, so we pass it as the naive timestamp
101+
// to be in sync with date range during calculation.
102+
return timeSeriesFromCustomInterval(this.granularityInterval, dateRange, moment(this.origin.format('YYYY-MM-DDTHH:mm:ss')), options);
90103
}
91104

92105
public resolvedGranularity(): string {

0 commit comments

Comments
 (0)