Functions for fetching the timezone for the current query. | (ns metabase.query-processor.timezone (:require [java-time.api :as t] [metabase.config :as config] [metabase.driver :as driver] [metabase.driver.util :as driver.u] [metabase.lib.metadata :as lib.metadata] [metabase.query-processor.store :as qp.store] [metabase.util.log :as log]) (:import (java.time ZonedDateTime))) |
(set! *warn-on-reflection* true) | |
(def ^:private ^:dynamic *report-timezone-id-override* nil) | |
(def ^:private ^:dynamic *database-timezone-id-override* nil) | |
(def ^:private ^:dynamic *results-timezone-id-override* nil) | |
TODO - consider making this | (defn- valid-timezone-id [timezone-id] (when (and (string? timezone-id) (seq timezone-id)) (try (t/zone-id timezone-id) timezone-id (catch Throwable _ (log/warnf "Invalid timezone ID '%s'" timezone-id) nil)))) |
(defn- report-timezone-id* [] (or *report-timezone-id-override* (driver/report-timezone))) | |
+----------------------------------------------------------------------------------------------------------------+ | Public Interface | +----------------------------------------------------------------------------------------------------------------+ | |
Timezone ID for the report timezone, if the current driver and database supports it. (If the current driver supports it, this is
bound by the | (defn report-timezone-id-if-supported (^String [] (report-timezone-id-if-supported driver/*driver* (lib.metadata/database (qp.store/metadata-provider)))) (^String [driver database] (when (driver.u/supports? driver :set-timezone database) (valid-timezone-id (report-timezone-id*))))) |
The timezone that the current database is in, as determined by the most recent sync. | (defn database-timezone-id (^String [] (database-timezone-id ::db-from-store)) (^String [database] (valid-timezone-id (or *database-timezone-id-override* (let [database (if (= database ::db-from-store) (lib.metadata/database (qp.store/metadata-provider)) database)] (:timezone database)))))) |
The system timezone of this Metabase instance. | (defn system-timezone-id ^String [] (.. (t/system-clock) getZone getId)) |
The timezone that we would like to run a query in, regardless of whether we are actually able to do so. This is
always equal to the value of the | (defn requested-timezone-id ^String [] (valid-timezone-id (report-timezone-id*))) |
The timezone that a query is actually ran in  report timezone, if set and supported by the current driver;
otherwise the timezone of the database (if known), otherwise the system timezone. Guaranteed to always return a
timezone ID  never returns | (defn results-timezone-id (^String [] (results-timezone-id driver/*driver* ::db-from-store)) (^String [database] (results-timezone-id (:engine database) database)) (^String [driver database & {:keys [use-report-timezone-id-if-unsupported?] :or {use-report-timezone-id-if-unsupported? false}}] (valid-timezone-id (or *results-timezone-id-override* (if use-report-timezone-id-if-unsupported? (valid-timezone-id (report-timezone-id*)) (report-timezone-id-if-supported driver database)) ;; don't actually fetch DB from store unless needed — that way if `*results-timezone-id-override*` is set we ;; don't need to init a store during tests (database-timezone-id database) ;; NOTE: if we don't have an explicit report-timezone then use the JVM timezone ;; this ensures alignment between the way dates are processed by JDBC and our returned data ;; GH issues: #2282, #2035 (system-timezone-id))))) |
Get the current moment in time adjusted to the results timezone ID, e.g. for relative datetime calculations. | (def ^ZonedDateTime now (comp (fn [timezone-id] (t/with-zone-same-instant (t/zoned-date-time) (t/zone-id timezone-id))) results-timezone-id)) |
normally I'd do this inline with the | (when config/is-dev? (alter-meta! #'now assoc :arglists (:arglists (meta #'results-timezone-id)))) |