Skip to content

Commit

Permalink
Handle new granularities
Browse files Browse the repository at this point in the history
  • Loading branch information
courtneyholcomb committed Jun 7, 2024
1 parent b30776a commit 006d76b
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,20 @@ class DateutilTimePeriodAdjuster(TimePeriodAdjuster):

def _relative_delta_for_window(self, time_granularity: TimeGranularity, count: int) -> relativedelta:
"""Relative-delta to cover time windows specified at different grains."""
if time_granularity is TimeGranularity.DAY:
if time_granularity is TimeGranularity.NANOSECOND:
# TODO: figure out a workaround when enabling time constraints
raise ValueError("`relativedelta` does not support nanoseconds.")
elif time_granularity is TimeGranularity.MICROSECOND:
return relativedelta(microseconds=count)
elif time_granularity is TimeGranularity.MILLISECOND:
return relativedelta(microseconds=count * 1000)
elif time_granularity is TimeGranularity.SECOND:
return relativedelta(seconds=count)
elif time_granularity is TimeGranularity.MINUTE:
return relativedelta(minutes=count)
elif time_granularity is TimeGranularity.HOUR:
return relativedelta(hours=count)
elif time_granularity is TimeGranularity.DAY:
return relativedelta(days=count)
elif time_granularity is TimeGranularity.WEEK:
return relativedelta(weeks=count)
Expand Down Expand Up @@ -53,8 +66,18 @@ def expand_time_constraint_to_fill_granularity(
def adjust_to_start_of_period(
self, time_granularity: TimeGranularity, date_to_adjust: datetime.datetime
) -> datetime.datetime:
if time_granularity is TimeGranularity.DAY:
# TODO: update these options once time constraints support a full timestamp
if (
time_granularity is TimeGranularity.NANOSECOND
or time_granularity is TimeGranularity.MICROSECOND
or time_granularity is TimeGranularity.MILLISECOND
or time_granularity is TimeGranularity.SECOND
or time_granularity is TimeGranularity.MINUTE
or time_granularity is TimeGranularity.HOUR
or time_granularity is TimeGranularity.DAY
):
return date_to_adjust

elif time_granularity is TimeGranularity.WEEK:
return date_to_adjust + relativedelta(weekday=dateutil.relativedelta.MO(-1))
elif time_granularity is TimeGranularity.MONTH:
Expand All @@ -77,8 +100,18 @@ def adjust_to_start_of_period(
def adjust_to_end_of_period(
self, time_granularity: TimeGranularity, date_to_adjust: datetime.datetime
) -> datetime.datetime:
if time_granularity is TimeGranularity.DAY:
# TODO: update these options once time constraints support a full timestamp
if (
time_granularity is TimeGranularity.NANOSECOND
or time_granularity is TimeGranularity.MICROSECOND
or time_granularity is TimeGranularity.MILLISECOND
or time_granularity is TimeGranularity.SECOND
or time_granularity is TimeGranularity.MINUTE
or time_granularity is TimeGranularity.HOUR
or time_granularity is TimeGranularity.DAY
):
return date_to_adjust

elif time_granularity is TimeGranularity.WEEK:
return date_to_adjust + relativedelta(weekday=dateutil.relativedelta.SU(1))
elif time_granularity is TimeGranularity.MONTH:
Expand Down
10 changes: 0 additions & 10 deletions metricflow-semantics/metricflow_semantics/time/time_constants.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
from __future__ import annotations

from dbt_semantic_interfaces.type_enums.time_granularity import TimeGranularity

# Python formatting string to use for converting datetime to ISO8601
ISO8601_PYTHON_FORMAT = "%Y-%m-%d"
ISO8601_PYTHON_TS_FORMAT = "%Y-%m-%d %H:%M:%S"

SUPPORTED_GRANULARITIES = [
TimeGranularity.DAY,
TimeGranularity.WEEK,
TimeGranularity.MONTH,
TimeGranularity.QUARTER,
TimeGranularity.YEAR,
]
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ def test_start_and_end_periods( # noqa: D103
rows: List[Tuple[str, ...]] = []
for date_time in date_times_to_check:
for time_granularity in TimeGranularity:
if time_granularity.to_int() < TimeGranularity.DAY.to_int():
continue
dateutil_start_of_period = dateutil_adjuster.adjust_to_start_of_period(time_granularity, date_time)
dateutil_end_of_period = dateutil_adjuster.adjust_to_end_of_period(time_granularity, date_time)
rows.append(
Expand Down
2 changes: 1 addition & 1 deletion metricflow/dataset/convert_semantic_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def _convert_time_dimension(
time_dimension_instances: List[TimeDimensionInstance] = []
select_columns: List[SqlSelectColumn] = []

defined_time_granularity = TimeGranularity.DAY
defined_time_granularity = DEFAULT_TIME_GRANULARITY
if dimension.type_params and dimension.type_params.time_granularity:
defined_time_granularity = dimension.type_params.time_granularity

Expand Down
7 changes: 4 additions & 3 deletions metricflow/plan_conversion/time_spine.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from dbt_semantic_interfaces.protocols import SemanticManifest
from dbt_semantic_interfaces.type_enums.time_granularity import TimeGranularity
from metricflow_semantics.mf_logging.pretty_print import mf_pformat
from metricflow_semantics.specs.spec_classes import DEFAULT_TIME_GRANULARITY

from metricflow.sql.sql_table import SqlTable

Expand All @@ -23,7 +24,7 @@ class TimeSpineSource:
# Name of the column in the table that contains the dates.
time_column_name: str = "ds"
# The time granularity of the dates in the spine table.
time_column_granularity: TimeGranularity = TimeGranularity.DAY
time_column_granularity: TimeGranularity = DEFAULT_TIME_GRANULARITY

@property
def spine_table(self) -> SqlTable:
Expand All @@ -37,10 +38,10 @@ def create_from_manifest(semantic_manifest: SemanticManifest) -> TimeSpineSource

if not (
len(time_spine_table_configurations) == 1
and time_spine_table_configurations[0].grain == TimeGranularity.DAY
and time_spine_table_configurations[0].grain == DEFAULT_TIME_GRANULARITY
):
raise NotImplementedError(
f"Only a single time spine table configuration with {TimeGranularity.DAY} is currently "
f"Only a single time spine table configuration with {DEFAULT_TIME_GRANULARITY} is currently "
f"supported. Got:\n"
f"{mf_pformat(time_spine_table_configurations)}"
)
Expand Down

0 comments on commit 006d76b

Please sign in to comment.