Add relative start param for time filters (#7525)

* Add relative start param for time filters

* Fix typo and add types to parse_human_datetime

* Add relative start/end to query_object

* Fix linting error
This commit is contained in:
Ville Brofeldt 2019-05-31 16:55:26 +03:00 committed by GitHub
parent dbdb6b093a
commit c1712e5d10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 50 additions and 17 deletions

View File

@ -51,9 +51,16 @@ class QueryObject:
is_prequery: bool = False,
columns: List[str] = None,
orderby: List[List] = None,
relative_start: str = app.config.get('DEFAULT_RELATIVE_START_TIME', 'today'),
relative_end: str = app.config.get('DEFAULT_RELATIVE_END_TIME', 'today'),
):
self.granularity = granularity
self.from_dttm, self.to_dttm = utils.get_since_until(time_range, time_shift)
self.from_dttm, self.to_dttm = utils.get_since_until(
relative_start=relative_start,
relative_end=relative_end,
time_range=time_range,
time_shift=time_shift,
)
self.is_timeseries = is_timeseries
self.time_range = time_range
self.time_shift = utils.parse_human_timedelta(time_shift)

View File

@ -599,8 +599,13 @@ BUG_REPORT_URL = None
DOCUMENTATION_URL = None
# 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
# 'today' means it is midnight (00:00:00) in the local timezone
# 'now' means it is relative to the query issue time
# If both start and end time is set to now, this will make the time
# filter a moving window. By only setting the end time to now,
# start time will be set to midnight, while end will be relative to
# the query issue time.
DEFAULT_RELATIVE_START_TIME = 'today'
DEFAULT_RELATIVE_END_TIME = 'today'
# Is epoch_s/epoch_ms datetime format supposed to be considered since UTC ?

View File

@ -237,14 +237,14 @@ def parse_human_datetime(s):
# when time is not extracted, we 'reset to midnight'
if parsed_flags & 2 == 0:
parsed_dttm = parsed_dttm.replace(hour=0, minute=0, second=0)
dttm = dttm_from_timtuple(parsed_dttm.utctimetuple())
dttm = dttm_from_timetuple(parsed_dttm.utctimetuple())
except Exception as e:
logging.exception(e)
raise ValueError("Couldn't parse date string [{}]".format(s))
return dttm
def dttm_from_timtuple(d: struct_time) -> datetime:
def dttm_from_timetuple(d: struct_time) -> datetime:
return datetime(
d.tm_year, d.tm_mon, d.tm_mday, d.tm_hour, d.tm_min, d.tm_sec)
@ -306,7 +306,7 @@ def parse_human_timedelta(s: str):
True
"""
cal = parsedatetime.Calendar()
dttm = dttm_from_timtuple(datetime.now().timetuple())
dttm = dttm_from_timetuple(datetime.now().timetuple())
d = cal.parse(s or '', dttm)[0]
d = datetime(d.tm_year, d.tm_mon, d.tm_mday, d.tm_hour, d.tm_min, d.tm_sec)
return d - dttm
@ -939,6 +939,7 @@ def get_since_until(time_range: Optional[str] = None,
since: Optional[str] = None,
until: Optional[str] = None,
time_shift: Optional[str] = None,
relative_start: Optional[str] = None,
relative_end: Optional[str] = None) -> Tuple[datetime, datetime]:
"""Return `since` and `until` date time tuple from string representations of
time_range, since, until and time_shift.
@ -965,13 +966,14 @@ def get_since_until(time_range: Optional[str] = None,
"""
separator = ' : '
relative_start = parse_human_datetime(relative_start if relative_start else 'today')
relative_end = parse_human_datetime(relative_end if relative_end else 'today')
common_time_frames = {
'Last day': (relative_end - relativedelta(days=1), relative_end), # noqa: T400
'Last week': (relative_end - relativedelta(weeks=1), relative_end), # noqa: T400
'Last month': (relative_end - relativedelta(months=1), relative_end), # noqa: E501, T400
'Last quarter': (relative_end - relativedelta(months=3), relative_end), # noqa: E501, T400
'Last year': (relative_end - relativedelta(years=1), relative_end), # noqa: T400
'Last day': (relative_start - relativedelta(days=1), relative_end), # noqa: T400
'Last week': (relative_start - relativedelta(weeks=1), relative_end), # noqa: E501, T400
'Last month': (relative_start - relativedelta(months=1), relative_end), # noqa: E501, T400
'Last quarter': (relative_start - relativedelta(months=3), relative_end), # noqa: E501, T400
'Last year': (relative_start - relativedelta(years=1), relative_end), # noqa: E501, T400
}
if time_range:
@ -988,10 +990,10 @@ def get_since_until(time_range: Optional[str] = None,
else:
rel, num, grain = time_range.split()
if rel == 'Last':
since = relative_end - relativedelta(**{grain: int(num)}) # noqa: T400
since = relative_start - relativedelta(**{grain: int(num)}) # noqa: T400
until = relative_end
else: # rel == 'Next'
since = relative_end
since = relative_start
until = relative_end + relativedelta(**{grain: int(num)}) # noqa: T400
else:
since = since or ''

View File

@ -59,6 +59,7 @@ from superset.utils.core import (
config = app.config
stats_logger = config.get('STATS_LOGGER')
relative_start = config.get('DEFAULT_RELATIVE_START_TIME', 'today')
relative_end = config.get('DEFAULT_RELATIVE_END_TIME', 'today')
METRIC_KEYS = [
@ -274,7 +275,8 @@ class BaseViz(object):
# default order direction
order_desc = form_data.get('order_desc', True)
since, until = utils.get_since_until(relative_end=relative_end,
since, until = utils.get_since_until(relative_start=relative_start,
relative_end=relative_end,
time_range=form_data.get('time_range'),
since=form_data.get('since'),
until=form_data.get('until'))
@ -800,7 +802,8 @@ class CalHeatmapViz(BaseViz):
values[str(v / 10**9)] = obj.get(metric)
data[metric] = values
start, end = utils.get_since_until(relative_end=relative_end,
start, end = utils.get_since_until(relative_start=relative_start,
relative_end=relative_end,
time_range=form_data.get('time_range'),
since=form_data.get('since'),
until=form_data.get('until'))

View File

@ -43,7 +43,9 @@ from superset.utils.core import (
def mock_parse_human_datetime(s):
if s in ['now', 'today']:
if s == 'now':
return datetime(2016, 11, 7, 9, 30, 10)
elif s == 'today':
return datetime(2016, 11, 7)
elif s == 'yesterday':
return datetime(2016, 11, 6)
@ -51,6 +53,8 @@ def mock_parse_human_datetime(s):
return datetime(2016, 11, 8)
elif s == 'Last year':
return datetime(2015, 11, 7)
elif s == 'Last week':
return datetime(2015, 10, 31)
elif s == 'Last 5 months':
return datetime(2016, 6, 7)
elif s == 'Next 5 months':
@ -600,7 +604,7 @@ class UtilsTestCase(unittest.TestCase):
self.assertEqual(result, expected)
result = get_since_until(' : now')
expected = None, datetime(2016, 11, 7)
expected = None, datetime(2016, 11, 7, 9, 30, 10)
self.assertEqual(result, expected)
result = get_since_until('yesterday : tomorrow')
@ -636,7 +640,19 @@ class UtilsTestCase(unittest.TestCase):
self.assertEqual(result, expected)
result = get_since_until(time_range='5 days : now')
expected = datetime(2016, 11, 2), datetime(2016, 11, 7)
expected = datetime(2016, 11, 2), datetime(2016, 11, 7, 9, 30, 10)
self.assertEqual(result, expected)
result = get_since_until('Last week', relative_end='now')
expected = datetime(2016, 10, 31), datetime(2016, 11, 7, 9, 30, 10)
self.assertEqual(result, expected)
result = get_since_until('Last week', relative_start='now')
expected = datetime(2016, 10, 31, 9, 30, 10), datetime(2016, 11, 7)
self.assertEqual(result, expected)
result = get_since_until('Last week', relative_start='now', relative_end='now')
expected = datetime(2016, 10, 31, 9, 30, 10), datetime(2016, 11, 7, 9, 30, 10)
self.assertEqual(result, expected)
with self.assertRaises(ValueError):