Skip to content

Commit 13b4635

Browse files
committed
add mysqlUseNamedTimezones flag
1 parent 3fa080d commit 13b4635

File tree

3 files changed

+68
-10
lines changed

3 files changed

+68
-10
lines changed

docs/pages/reference/configuration/environment-variables.mdx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,16 @@ The cluster name to use when connecting to [Materialize](/product/configuration/
663663
| --------------------------------------------------------- | ---------------------- | --------------------- |
664664
| A valid Materialize cluster name | N/A | N/A |
665665

666+
## `CUBEJS_DB_MYSQL_USE_NAMED_TIMEZONES`
667+
668+
This flag controls how timezones are passed to CONVERT_TZ. If it is set to TRUE - timezone names will be used.
669+
IF it is set to FALSE - numeric offsets will be passed instead. To use named timezones, MySQL Server needs
670+
to be [configured][mysql-server-tz-support] properly.
671+
672+
| Possible Values | Default in Development | Default in Production |
673+
| ------------------------------------- | ---------------------- | --------------------- |
674+
| Whether to use named timezones or not | `false` | `false` |
675+
666676
## `CUBEJS_DB_SNOWFLAKE_ACCOUNT`
667677

668678
The Snowflake account identifier to use when connecting to the database.
@@ -1612,3 +1622,4 @@ The port for a Cube deployment to listen to API connections on.
16121622
[ref-sql-api]: /product/apis-integrations/sql-api
16131623
[ref-sql-api-streaming]: /product/apis-integrations/sql-api#streaming
16141624
[ref-row-limit]: /product/apis-integrations/queries#row-limit
1625+
[mysql-server-tz-support]: https://dev.mysql.com/doc/refman/8.4/en/time-zone-support.html

packages/cubejs-backend-shared/src/env.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,44 @@ const variables: Record<string, (...args: any) => any> = {
866866
return undefined;
867867
},
868868

869+
/** ****************************************************************
870+
* MySQL Driver *
871+
***************************************************************** */
872+
873+
/**
874+
* Use timezone names for date/time conversions.
875+
* Defaults to FALSE, meaning that numeric offsets for timezone will be used.
876+
* @see https://dev.mysql.com/doc/refman/8.4/en/date-and-time-functions.html#function_convert-tz
877+
* @see https://dev.mysql.com/doc/refman/8.4/en/time-zone-support.html
878+
*/
879+
mysqlUseNamedTimezones: ({ dataSource }: { dataSource: string }) => {
880+
const val = process.env[
881+
keyByDataSource(
882+
'CUBEJS_DB_MYSQL_USE_NAMED_TIMEZONES',
883+
dataSource,
884+
)
885+
];
886+
887+
if (val) {
888+
if (val.toLocaleLowerCase() === 'true') {
889+
return true;
890+
} else if (val.toLowerCase() === 'false') {
891+
return false;
892+
} else {
893+
throw new TypeError(
894+
`The ${
895+
keyByDataSource(
896+
'CUBEJS_DB_MYSQL_USE_NAMED_TIMEZONES',
897+
dataSource,
898+
)
899+
} must be either 'true' or 'false'.`
900+
);
901+
}
902+
} else {
903+
return false;
904+
}
905+
},
906+
869907
/** ****************************************************************
870908
* Databricks Driver *
871909
***************************************************************** */

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

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import moment from 'moment-timezone';
2-
3-
import { parseSqlInterval } from '@cubejs-backend/shared';
4-
2+
import { getEnv, parseSqlInterval } from '@cubejs-backend/shared';
53
import { BaseQuery } from './BaseQuery';
64
import { BaseFilter } from './BaseFilter';
75
import { UserError } from '../compiler/UserError';
@@ -26,39 +24,50 @@ class MysqlFilter extends BaseFilter {
2624
}
2725

2826
export class MysqlQuery extends BaseQuery {
27+
private readonly useNamedTimezones: boolean;
28+
29+
public constructor(compilers: any, options: any) {
30+
super(compilers, options);
31+
32+
this.useNamedTimezones = getEnv('mysqlUseNamedTimezones', { dataSource: this.dataSource });
33+
}
34+
2935
public newFilter(filter) {
3036
return new MysqlFilter(this, filter);
3137
}
3238

33-
public castToString(sql) {
39+
public castToString(sql: string) {
3440
return `CAST(${sql} as CHAR)`;
3541
}
3642

37-
public convertTz(field) {
43+
public convertTz(field: string) {
44+
if (this.useNamedTimezones) {
45+
return `CONVERT_TZ(${field}, @@session.time_zone, '${this.timezone}')`;
46+
}
3847
return `CONVERT_TZ(${field}, @@session.time_zone, '${moment().tz(this.timezone).format('Z')}')`;
3948
}
4049

41-
public timeStampCast(value) {
50+
public timeStampCast(value: string) {
4251
return `TIMESTAMP(convert_tz(${value}, '+00:00', @@session.time_zone))`;
4352
}
4453

4554
public timestampFormat() {
4655
return 'YYYY-MM-DDTHH:mm:ss.SSS';
4756
}
4857

49-
public dateTimeCast(value) {
58+
public dateTimeCast(value: string) {
5059
return `TIMESTAMP(${value})`;
5160
}
5261

53-
public subtractInterval(date, interval) {
62+
public subtractInterval(date: string, interval: string) {
5463
return `DATE_SUB(${date}, INTERVAL ${this.formatInterval(interval)})`;
5564
}
5665

57-
public addInterval(date, interval) {
66+
public addInterval(date: string, interval: string) {
5867
return `DATE_ADD(${date}, INTERVAL ${this.formatInterval(interval)})`;
5968
}
6069

61-
public timeGroupedColumn(granularity, dimension) {
70+
public timeGroupedColumn(granularity: string, dimension) {
6271
return `CAST(${GRANULARITY_TO_INTERVAL[granularity](dimension)} AS DATETIME)`;
6372
}
6473

0 commit comments

Comments
 (0)