feat(time_comparison): Support all date formats when computing custom and inherit offsets (#30002)

This commit is contained in:
Antonio Rivero
2024-08-23 15:32:25 +02:00
committed by GitHub
parent ce72a0ac27
commit bc6d2dba37
10 changed files with 216 additions and 167 deletions

View File

@@ -19,6 +19,7 @@ from __future__ import annotations
import copy
import logging
import re
from datetime import datetime
from typing import Any, cast, ClassVar, TYPE_CHECKING, TypedDict
import numpy as np
@@ -369,6 +370,38 @@ class QueryContextProcessor:
axis=1,
)
def is_valid_date(self, date_string: str) -> bool:
try:
# Attempt to parse the string as a date in the format YYYY-MM-DD
datetime.strptime(date_string, "%Y-%m-%d")
return True
except ValueError:
# If parsing fails, it's not a valid date in the format YYYY-MM-DD
return False
def get_offset_custom_or_inherit(
self,
offset: str,
outer_from_dttm: datetime,
outer_to_dttm: datetime,
) -> str:
"""
Get the time offset for custom or inherit.
:param offset: The offset string.
:param outer_from_dttm: The outer from datetime.
:param outer_to_dttm: The outer to datetime.
:returns: The time offset.
"""
if offset == "inherit":
# return the difference in days between the from and the to dttm formatted as a string with the " days ago" suffix
return f"{(outer_to_dttm - outer_from_dttm).days} days ago"
if self.is_valid_date(offset):
# return the offset as the difference in days between the outer from dttm and the offset date (which is a YYYY-MM-DD string) formatted as a string with the " days ago" suffix
offset_date = datetime.strptime(offset, "%Y-%m-%d")
return f"{(outer_from_dttm - offset_date).days} days ago"
return ""
def processing_time_offsets( # pylint: disable=too-many-locals,too-many-statements
self,
df: pd.DataFrame,
@@ -409,6 +442,13 @@ class QueryContextProcessor:
# time_offsets: ['1 year ago'],
# filters: [{col: 'dttm_col', op: 'TEMPORAL_RANGE', val: '2020 : 2021'}],
# }
original_offset = offset
if self.is_valid_date(offset) or offset == "inherit":
offset = self.get_offset_custom_or_inherit(
offset,
outer_from_dttm,
outer_to_dttm,
)
query_object_clone.from_dttm = get_past_or_future(
offset,
outer_from_dttm,
@@ -454,9 +494,19 @@ class QueryContextProcessor:
if flt.get("col") != x_axis_label
]
# Inherit or custom start dates might compute the same offset but the response cannot be given
# using cached data unless you are using the same date of inherited range, that's why we
# set the cache cache using a custom key that includes the original offset and the computed offset
# for those two scenarios, the rest of the scenarios will use the original offset as cache key
cached_time_offset_key = (
offset if offset == original_offset else f"{offset}_{original_offset}"
)
# `offset` is added to the hash function
cache_key = self.query_cache_key(
query_object_clone, time_offset=offset, time_grain=time_grain
query_object_clone,
time_offset=cached_time_offset_key,
time_grain=time_grain,
)
cache = QueryCacheManager.get(
cache_key, CacheRegion.DATA, query_context.force
@@ -471,7 +521,7 @@ class QueryContextProcessor:
query_object_clone_dct = query_object_clone.to_dict()
# rename metrics: SUM(value) => SUM(value) 1 year ago
metrics_mapping = {
metric: TIME_COMPARISON.join([metric, offset])
metric: TIME_COMPARISON.join([metric, original_offset])
for metric in metric_names
}