Skip to content

Commit b8d6d94

Browse files
committed
add mysqlUseNamedTimezones flag
1 parent de7332f commit b8d6d94

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
@@ -603,6 +603,16 @@ The cluster name to use when connecting to [Materialize](/product/configuration/
603603
| --------------------------------------------------------- | ---------------------- | --------------------- |
604604
| A valid Materialize cluster name | N/A | N/A |
605605

606+
## `CUBEJS_DB_MYSQL_USE_NAMED_TIMEZONES`
607+
608+
This flag controls how timezones are passed to CONVERT_TZ. If it is set to TRUE - timezone names will be used.
609+
IF it is set to FALSE - numeric offsets will be passed instead. To use named timezones, MySQL Server needs
610+
to be [configured][mysql-server-tz-support] properly.
611+
612+
| Possible Values | Default in Development | Default in Production |
613+
| ------------------------------------- | ---------------------- | --------------------- |
614+
| Whether to use named timezones or not | `false` | `false` |
615+
606616
## `CUBEJS_DB_SNOWFLAKE_ACCOUNT`
607617

608618
The Snowflake account identifier to use when connecting to the database.
@@ -1552,3 +1562,4 @@ The port for a Cube deployment to listen to API connections on.
15521562
[ref-sql-api]: /product/apis-integrations/sql-api
15531563
[ref-sql-api-streaming]: /product/apis-integrations/sql-api#streaming
15541564
[ref-row-limit]: /product/apis-integrations/queries#row-limit
1565+
[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
@@ -853,6 +853,44 @@ const variables: Record<string, (...args: any) => any> = {
853853
return undefined;
854854
},
855855

856+
/** ****************************************************************
857+
* MySQL Driver *
858+
***************************************************************** */
859+
860+
/**
861+
* Use timezone names for date/time conversions.
862+
* Defaults to FALSE, meaning that numeric offsets for timezone will be used.
863+
* @see https://dev.mysql.com/doc/refman/8.4/en/date-and-time-functions.html#function_convert-tz
864+
* @see https://dev.mysql.com/doc/refman/8.4/en/time-zone-support.html
865+
*/
866+
mysqlUseNamedTimezones: ({ dataSource }: { dataSource: string }) => {
867+
const val = process.env[
868+
keyByDataSource(
869+
'CUBEJS_DB_MYSQL_USE_NAMED_TIMEZONES',
870+
dataSource,
871+
)
872+
];
873+
874+
if (val) {
875+
if (val.toLocaleLowerCase() === 'true') {
876+
return true;
877+
} else if (val.toLowerCase() === 'false') {
878+
return false;
879+
} else {
880+
throw new TypeError(
881+
`The ${
882+
keyByDataSource(
883+
'CUBEJS_DB_MYSQL_USE_NAMED_TIMEZONES',
884+
dataSource,
885+
)
886+
} must be either 'true' or 'false'.`
887+
);
888+
}
889+
} else {
890+
return false;
891+
}
892+
},
893+
856894
/** ****************************************************************
857895
* Databricks Driver *
858896
***************************************************************** */

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)