diff --git a/superset/assets/src/explore/components/controls/DateFilterControl.jsx b/superset/assets/src/explore/components/controls/DateFilterControl.jsx index 9e07b99037cac..4d210c433c2f6 100644 --- a/superset/assets/src/explore/components/controls/DateFilterControl.jsx +++ b/superset/assets/src/explore/components/controls/DateFilterControl.jsx @@ -66,8 +66,15 @@ const COMMON_TIME_FRAMES = [ const TIME_GRAIN_OPTIONS = ['seconds', 'minutes', 'hours', 'days', 'weeks', 'months', 'years']; const MOMENT_FORMAT = 'YYYY-MM-DD[T]HH:mm:ss'; -const DEFAULT_SINCE = moment().startOf('day').subtract(7, 'days').format(MOMENT_FORMAT); -const DEFAULT_UNTIL = moment().startOf('day').format(MOMENT_FORMAT); +const DEFAULT_SINCE = moment() + .utc() + .startOf('day') + .subtract(7, 'days') + .format(MOMENT_FORMAT); +const DEFAULT_UNTIL = moment() + .utc() + .startOf('day') + .format(MOMENT_FORMAT); const SEPARATOR = ' : '; const FREEFORM_TOOLTIP = t( 'Superset supports smart date parsing. Strings like `last sunday` or ' + @@ -109,8 +116,12 @@ function getStateFromCommonTimeFrame(value) { tab: TABS.DEFAULTS, type: TYPES.DEFAULTS, common: value, - since: moment().startOf('day').subtract(1, units).format(MOMENT_FORMAT), - until: moment().startOf('day').format(MOMENT_FORMAT), + since: moment() + .utc() + .startOf('day') + .subtract(1, units) + .format(MOMENT_FORMAT), + until: moment().utc().startOf('day').format(MOMENT_FORMAT), }; } @@ -119,13 +130,15 @@ function getStateFromCustomRange(value) { let since; let until; if (rel === RELATIVE_TIME_OPTIONS.LAST) { - until = moment().startOf('day').format(MOMENT_FORMAT); + until = moment().utc().startOf('day').format(MOMENT_FORMAT); since = moment() + .utc() .startOf('day') .subtract(num, grain) .format(MOMENT_FORMAT); } else { until = moment() + .utc() .startOf('day') .add(num, grain) .format(MOMENT_FORMAT); diff --git a/superset/assets/src/explore/controls.jsx b/superset/assets/src/explore/controls.jsx index 19773bb411c6a..40e1233c78024 100644 --- a/superset/assets/src/explore/controls.jsx +++ b/superset/assets/src/explore/controls.jsx @@ -1026,6 +1026,14 @@ export const controls = { freeForm: true, label: t('Time range'), default: t('No filter'), + description: t( + 'The time range for the visualization. All relative times, e.g. "Last month", ' + + '"Last 7 days", "now", etc. are evaluated on the server using the server\'s ' + + 'local time (sans timezone). All tooltips and placeholder times are expressed ' + + 'in UTC (sans timezone). The timestamps are then evaluated by the database ' + + 'using the engine\'s local timezone. Note one can explicitly set the timezone ' + + 'per the ISO 8601 format if specifying either the start and/or end time.', + ), }, max_bubble_size: { diff --git a/superset/config.py b/superset/config.py index 9d53858e6769e..d0ba32716f66a 100644 --- a/superset/config.py +++ b/superset/config.py @@ -597,13 +597,7 @@ class CeleryConfig(object): # What is the Last N days relative in the time selector to: # 'today' means it is midnight (00:00:00) of today in the local timezone # 'now' means it is relative to the query issue time -DEFAULT_RELATIVE_END_TIME = 'today' - -# Is epoch_s/epoch_ms datetime format supposed to be considered since UTC ? -# If not, it is sassumed then the epoch_s/epoch_ms is seconds since 1/1/1970 -# localtime (in the tz where the superset webserver is running) -IS_EPOCH_S_TRULY_UTC = False - +DEFAULT_RELATIVE_END_TIME = 'now' # set on IS_KNOX_SSO_ENABLED here ,because of unit test cases and rest KNOX varibales are defined in superset_config.py IS_KNOX_SSO_ENABLED = False diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index d3827f545adf2..18ff8cc15fd66 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -137,13 +137,12 @@ def datasource(self): return self.table def get_time_filter(self, start_dttm, end_dttm): - is_epoch_in_utc = config.get('IS_EPOCH_S_TRULY_UTC', False) col = self.get_sqla_col(label='__time') l = [] # noqa: E741 if start_dttm: - l.append(col >= text(self.dttm_sql_literal(start_dttm, is_epoch_in_utc))) + l.append(col >= text(self.dttm_sql_literal(start_dttm))) if end_dttm: - l.append(col <= text(self.dttm_sql_literal(end_dttm, is_epoch_in_utc))) + l.append(col <= text(self.dttm_sql_literal(end_dttm))) return and_(*l) def get_timestamp_expression(self, time_grain): @@ -174,7 +173,7 @@ def lookup_obj(lookup_column): TableColumn.column_name == lookup_column.column_name).first() return import_datasource.import_simple_obj(db.session, i_column, lookup_obj) - def dttm_sql_literal(self, dttm, is_epoch_in_utc): + def dttm_sql_literal(self, dttm): """Convert datetime object to a SQL expression string If database_expression is empty, the internal dttm @@ -187,11 +186,7 @@ def dttm_sql_literal(self, dttm, is_epoch_in_utc): if self.database_expression: return self.database_expression.format(dttm.strftime('%Y-%m-%d %H:%M:%S')) elif tf: - if is_epoch_in_utc: - seconds_since_epoch = dttm.timestamp() - else: - seconds_since_epoch = (dttm - datetime(1970, 1, 1)).total_seconds() - seconds_since_epoch = int(seconds_since_epoch) + seconds_since_epoch = int(dttm.timestamp()) if tf == 'epoch_s': return str(seconds_since_epoch) elif tf == 'epoch_ms':