Every time series in the Semantic Layer is grouped by metric_time plus a grain: metric_time__month, metric_time__quarter, metric_time__year. The name is the same for every metric, which is what lets orders, signups and balances share one axis even though each is counted by its own date.

Copy and paste

dbt sl query --metrics revenue --group-by metric_time__month --order-by metric_time__month
dbt sl query --metrics revenue,order_count,signups --group-by metric_time__quarter
dbt sl query --metrics revenue --group-by metric_time__year,customer__country --order-by metric_time__year,-revenue

With dbt Core and MetricFlow, use mf query and --order instead of --order-by.

metric_time__quarter      revenue    order_count    signups
----------------------  ---------  -------------  ---------
2025-01-01T00:00:00           310              3          3
2025-04-01T00:00:00           340              4          1
2025-07-01T00:00:00           200              2
2025-10-01T00:00:00           490              3
2026-01-01T00:00:00           340              3          2
2026-04-01T00:00:00           550              4

The grains

day, week, month, quarter and year, plus finer ones (hour, minute…) if the time dimension has them, and any custom granularity of the time spine, such as metric_time__fiscal_year. A grain can’t be finer than the column’s granularity.

metric_time without a grain uses the finest grain available, a day here. Each period is labelled by its first moment: 2025-04-01T00:00:00 is the second quarter of 2025. Format it in the BI tool.

One timeline for several metrics

In the quarterly output, revenue and order_count are grouped by order date and signups by signup date, because metric_time means each metric’s own default time dimension. Empty cells are periods in which a metric has no data; the results are combined with a full outer join, so no period is lost.

Another date of the same model

order__order_date__month and order__shipped_date__month group by a named time dimension instead. They work for metrics of that model and of the models it joins, but not across unrelated metrics, and features that rely on metric_time (cumulative metrics, offsets, --start-time) keep using the metric’s own date.

Several grains at once

mf query --metrics revenue --group-by metric_time__year,metric_time__month --start-time 2026-03-01
metric_time__month    metric_time__year      revenue
--------------------  -------------------  ---------
2026-03-01T00:00:00   2026-01-01T00:00:00        100
2026-04-01T00:00:00   2026-01-01T00:00:00         80
2026-05-01T00:00:00   2026-01-01T00:00:00        470

Useful for BI tools that build a year–month hierarchy from two columns.

Sorting

--order-by (--order with mf) takes a comma-separated list; a - before a name sorts descending: metric_time__month,-revenue sorts by month, then by revenue from the highest. Without it, rows come back in whatever order the warehouse returns them, which is often not chronological.

Month of year

Seasonality questions (“which month sells best across years?”) need the month number regardless of year. The CLI didn’t accept metric_time__extract_month (“does not match any of the known formats”). Add a month-number dimension to the model with derived_semantics, or let the BI tool extract it from the monthly series.

Tested with dbt Core 1.12 and MetricFlow 0.213 on DuckDB; the dbt sl options come from the dbt documentation.

References