diff --git a/.github/actions/e2e-prepare-containers/action.yml b/.github/actions/e2e-prepare-containers/action.yml index d00f29e227d5aca57f1e201a42280b9d42331d06..fe5fefe72e03d5ac74af629b601f5677f3ab4eb3 100644 --- a/.github/actions/e2e-prepare-containers/action.yml +++ b/.github/actions/e2e-prepare-containers/action.yml @@ -66,14 +66,14 @@ runs: if ${{ inputs.postgres }}; then echo -e "${Y}Starting postgres container..." && - docker run -d -p 5404:5432 metabase/qa-databases:postgres-sample-12 && + docker run -d -p 5404:5432 -e TZ='US/Pacific' metabase/qa-databases:postgres-sample-12 && while ! nc -z localhost 5404; do sleep 1; done && echo -e "${G}Postgres is up and running!" fi if ${{ inputs.mysql }}; then echo -e "${Y}Starting mysql container..." && - docker run -d -p 3304:3306 metabase/qa-databases:mysql-sample-8 && + docker run -d -p 3304:3306 -e TZ='US/Pacific' metabase/qa-databases:mysql-sample-8 && while ! nc -z localhost 3304; do sleep 1; done && echo -e "${G}MySQL is up and running!" fi diff --git a/e2e/test/scenarios/actions/actions-on-dashboards.cy.spec.js b/e2e/test/scenarios/actions/actions-on-dashboards.cy.spec.js index 87007c77f7a7262704a0a83af710187559ed628d..af7ba4dcedff4499ed0fe0fcf7dced5378d081a7 100644 --- a/e2e/test/scenarios/actions/actions-on-dashboards.cy.spec.js +++ b/e2e/test/scenarios/actions/actions-on-dashboards.cy.spec.js @@ -747,39 +747,20 @@ const MODEL_NAME = "Test Action Model"; newValue: newTime, }); - // only postgres has timezone-aware columns - // the instance is in US/Pacific so it's -8 hours - if (dialect === "postgres") { - changeValue({ - fieldName: "DatetimeTZ", - fieldType: "datetime-local", - oldValue: "2020-01-01T00:35:55", - newValue: newTime, - }); + changeValue({ + fieldName: "DatetimeTZ", + fieldType: "datetime-local", + oldValue: oldRow.datetimeTZ.replace(" ", "T"), + newValue: newTime, + }); - changeValue({ - fieldName: "TimestampTZ", - fieldType: "datetime-local", - oldValue: "2020-01-01T00:35:55", - newValue: newTime, - }); - } - - if (dialect === "mysql") { - changeValue({ - fieldName: "DatetimeTZ", - fieldType: "datetime-local", - oldValue: oldRow.datetimeTZ.replace(" ", "T"), - newValue: newTime, - }); + changeValue({ + fieldName: "TimestampTZ", + fieldType: "datetime-local", + oldValue: oldRow.timestampTZ.replace(" ", "T"), + newValue: newTime, + }); - changeValue({ - fieldName: "TimestampTZ", - fieldType: "datetime-local", - oldValue: oldRow.timestampTZ.replace(" ", "T"), - newValue: newTime, - }); - } cy.button("Update").click(); }); diff --git a/e2e/test/scenarios/docker-compose.yml b/e2e/test/scenarios/docker-compose.yml index ed9729fa994a615c927c66da681457f28f8e6d0a..98de38f11abb4473f8ae83c0ea514cd16860efbd 100644 --- a/e2e/test/scenarios/docker-compose.yml +++ b/e2e/test/scenarios/docker-compose.yml @@ -2,6 +2,8 @@ version: '3.9' services: postgres-sample: + environment: + - TZ=US/Pacific image: metabase/qa-databases:postgres-sample-12 ports: - "5404:5432" @@ -10,6 +12,8 @@ services: ports: - 27004:27017 mysql-sample: + environment: + - TZ=US/Pacific image: metabase/qa-databases:mysql-sample-8 ports: - 3304:3306 diff --git a/modules/drivers/oracle/src/metabase/driver/oracle.clj b/modules/drivers/oracle/src/metabase/driver/oracle.clj index 3a9191c54a474f29ab1ba3d0748c425c261f99a3..1af1a51028c068532e4a4031168397b18c244d41 100644 --- a/modules/drivers/oracle/src/metabase/driver/oracle.clj +++ b/modules/drivers/oracle/src/metabase/driver/oracle.clj @@ -620,14 +620,14 @@ (defmethod unprepare/unprepare-value [:oracle OffsetDateTime] [_ t] - (let [s (-> (t/format "yyyy-MM-dd HH:mm:ss.SSS ZZZZZ" t) - ;; Oracle doesn't like `Z` to mean UTC - (str/replace #"Z$" "UTC"))] - (format "timestamp '%s'" s))) + ;; Oracle doesn't like `Z` to mean UTC + (format "timestamp '%s'" (-> (t/format "yyyy-MM-dd HH:mm:ss.SSS ZZZZZ" t) + (str/replace #" Z$" " UTC")))) (defmethod unprepare/unprepare-value [:oracle ZonedDateTime] [_ t] - (format "timestamp '%s'" (t/format "yyyy-MM-dd HH:mm:ss.SSS VV" t))) + (format "timestamp '%s'" (-> (t/format "yyyy-MM-dd HH:mm:ss.SSS VV" t) + (str/replace #" Z$" " UTC")))) (defmethod unprepare/unprepare-value [:oracle Instant] [driver t] diff --git a/modules/drivers/snowflake/src/metabase/driver/snowflake.clj b/modules/drivers/snowflake/src/metabase/driver/snowflake.clj index 369d8142d367429e31427380c19d60905cad77d8..9d66493ec3bff0e2fc95c873c4e97de23d987229 100644 --- a/modules/drivers/snowflake/src/metabase/driver/snowflake.clj +++ b/modules/drivers/snowflake/src/metabase/driver/snowflake.clj @@ -526,10 +526,10 @@ (sql-jdbc.execute/do-with-connection-with-options driver database nil (fn [^java.sql.Connection conn] - (with-open [stmt (.prepareStatement conn "show parameters like 'TIMEZONE';") + (with-open [stmt (.prepareStatement conn "show parameters like 'TIMEZONE' in user;") rset (.executeQuery stmt)] (when (.next rset) - (.getString rset "default")))))) + (.getString rset "value")))))) (defmethod sql-jdbc.sync/excluded-schemas :snowflake [_] diff --git a/modules/drivers/snowflake/test/metabase/test/data/snowflake.clj b/modules/drivers/snowflake/test/metabase/test/data/snowflake.clj index 2ad911a37c86529a7207361a5aeeeb535fbbb4b2..b5c40940db64504a582d33e7cfc91e580becccd3 100644 --- a/modules/drivers/snowflake/test/metabase/test/data/snowflake.clj +++ b/modules/drivers/snowflake/test/metabase/test/data/snowflake.clj @@ -144,12 +144,26 @@ (delete-old-datasets!) (reset! deleted-old-datasets? true))))) +(defn- set-current-user-timezone! + [timezone] + (sql-jdbc.execute/do-with-connection-with-options + :snowflake + (no-db-connection-spec) + {:write? true} + (fn [^java.sql.Connection conn] + (with-open [stmt (.createStatement conn)] + (.execute stmt (format "ALTER USER SET TIMEZONE = '%s';" timezone)))))) + (defmethod tx/create-db! :snowflake [driver db-def & options] ;; qualify the DB name with the unique prefix (let [db-def (update db-def :database-name qualified-db-name)] ;; clean up any old datasets that should be deleted (delete-old-datsets-if-needed!) + ;; Snowflake by default uses America/Los_Angeles timezone. See https://docs.snowflake.com/en/sql-reference/parameters#timezone. + ;; We expect UTC in tests. Hence fixing [[metabase.query-processor.timezone/database-timezone-id]] (PR #36413) + ;; produced lot of failures. Following expression addresses that, setting timezone for the test user. + (set-current-user-timezone! "UTC") ;; now call the default impl for SQL JDBC drivers (apply (get-method tx/create-db! :sql-jdbc/test-extensions) driver db-def options))) diff --git a/src/metabase/driver/h2.clj b/src/metabase/driver/h2.clj index 49304f48ea1117ca8ace18f86b70089325fb7305..5eb10468578fd8de1b893b05bcf8bf00475138c6 100644 --- a/src/metabase/driver/h2.clj +++ b/src/metabase/driver/h2.clj @@ -312,15 +312,10 @@ message)) (defmethod driver/db-default-timezone :h2 - [driver database] - (sql-jdbc.execute/do-with-connection-with-options - driver database nil - (fn [^java.sql.Connection conn] - (with-open [stmt (.prepareStatement conn "select current_timestamp();") - rset (.executeQuery stmt)] - (when (.next rset) - (when-let [zoned-date-time (.getObject rset 1 java.time.ZonedDateTime)] - (t/zone-id zoned-date-time))))))) + [_driver _database] + ;; Based on this answer https://stackoverflow.com/a/18883531 and further experiments, h2 uses timezone of the jvm + ;; where the driver is loaded. + (System/getProperty "user.timezone")) ;;; +----------------------------------------------------------------------------------------------------------------+ diff --git a/src/metabase/lib/metadata/jvm.clj b/src/metabase/lib/metadata/jvm.clj index 7f964ed16ac33afad7337f93b37cbb79783f5183..6ceeb40c2b0acfd23d1843b2fa2a1efd935d3422 100644 --- a/src/metabase/lib/metadata/jvm.clj +++ b/src/metabase/lib/metadata/jvm.clj @@ -65,7 +65,7 @@ #_resolved-query clojure.lang.IPersistentMap] [query-type model parsed-args honeysql] (merge (next-method query-type model parsed-args honeysql) - {:select [:id :engine :name :dbms_version :settings :is_audit :details]})) + {:select [:id :engine :name :dbms_version :settings :is_audit :details :timezone]})) (t2/define-after-select :metadata/database [database]