Period axes and comparisons
A period axis defines which dates to select and how to group them. A measure binding can choose the offset used for a prior-period comparison. Period axes, comparison settings and business questions require Business Questions to be enabled. Existing definitions remain stored when it is disabled; they cannot be edited or queried until it is enabled again. You can still save unrelated draft edits, but publishing a layer containing period definitions requires the feature to be enabled. Ordinary relative-date filters remain available independently.
Author through MCP
Section titled “Author through MCP”With Business Questions enabled, Nash tool contract 2.8.0 lets you create reusable Time Axes and
comparison measures through the existing dimension and measure authoring tools. Reads require
sl:read and changes require sl:write, along with access to the semantic layer.
- Call
astrato_semantic_layer_prepare_dimension_changewith your date-field concept. Reuse an existing suitable axis when one is available. Otherwise callastrato_semantic_layer_apply_dimension_changewith aperiodAxisdefinition. - Call
astrato_semantic_layer_prepare_measure_changeafter the axis exists. ItsperiodAxesentries list the stored axes, their source views, windows, grouping levels and reachability from the candidate fields or measures. An axis needs at least one source that joins to the measure’s fields, including fields reached through existing-measure references. Other sources on that axis do not need to join to those fields. - Call
astrato_semantic_layer_apply_measure_changewith the chosen axis’s business name indefinition.periodComparison.
The following examples show each apply call’s change argument. Also pass the semanticLayerId
and preparedTarget from the corresponding prepare response, and copy its revision into
expectedRevision. For creation, preparedTarget is null. Prepare the measure after creating
the axis so its revision includes that change.
Create a monthly axis over the date field returned by dimension preparation:
{ "operation": "create", "name": "Order Timeline", "definition": { "kind": "periodAxis", "field": { "view": "Sales", "field": "Date" }, "period": "last12Months", "level": "month" }}Then create a growth measure, using the exact field and supported aggregation returned by measure
preparation. A percentage format displays a growth value such as 0.25 as 25.0%:
{ "operation": "create", "name": "Revenue growth", "definition": { "inputs": [ { "id": "amount", "kind": "aggregate", "field": { "view": "Sales", "field": "Amount" }, "aggregation": "SUM" } ], "format": { "mode": "custom", "pattern": "0.0%" }, "periodComparison": { "type": "growth", "timeAxis": "Order Timeline" } }}The comparison type is current, value, diff, ratio or growth. You may also supply:
alignment:calendar(the default) orweekday.baseline: an optionalgrainand signed integeroffset. The offset defaults to-1; negative values look back and positive values look ahead. Omitting the grain uses a named window’s previous interval, or the unit of a relative window.window: optionalperiod,levelandperiodEndoverrides for this measure. Omitted properties inherit the axis settings. The effective period, grouping and baseline must be compatible; the same validation applies as for saved definitions below.
To change an existing comparison, prepare that measure and send a patch such as:
{ "operation": "patch", "name": "Revenue growth", "patch": { "periodComparison": { "mode": "set", "type": "growth", "timeAxis": "Order Timeline", "alignment": "weekday", "baseline": { "grain": "year", "offset": -2 } } }}set supplies the complete comparison configuration: omitted alignment, baseline and window
settings return to their defaults. Omitting periodComparison entirely from a formula patch or
replacement preserves the stored comparison and bindings. To remove the comparison and its
baseline, send patch.periodComparison: { "mode": "clear" }. This preserves independently
saved window overrides and nested reductions, including a reduction’s inner axis settings.
If the measure binding only supplied a comparison baseline, clearing removes that binding too.
null is not a clear operation. Formula patches use patch.calculation; comparison changes go
alongside it in patch.periodComparison.
This authoring surface accepts one date field when defining an axis. It can use an existing axis
with several sources, but it cannot author comparison scope (additionalDimensions) or explicit
nested reductions. A stored comparison scope is preserved when setting or replacing the comparison.
A saved nested reduction also survives replacement. Changing the comparison’s Time intelligence axis moves
the reduction’s references to that axis while keeping its aggregation and inner window overrides.
The resulting settings must remain compatible with the new axis; incompatible edits are rejected.
These calls commit draft changes only. Publish separately before querying newly created stored
items through the data tools. SQL compilation or a dry run does not verify datasource execution.
Query with a period axis
Section titled “Query with a period axis”astrato_data_execute_query runs a period axis defined inline in the query, or a stored axis referenced by name. Valid period values and the level each allows are listed under the date a period is read as of. A saved question takes the same definition the query does, including orderBy, output and advancedCalculation.
- Limit a measure to the axis window with a comparison. Give the main value
"periodComparison": { "type": "current", "reference": { "dimension": "<axis key>" } }. A measure without aperiodComparisonis not tied to the window. - “Current” or “this” year, quarter, month or week means to date. Nash and MCP clients read it as
yearToDate,quarterToDate,monthToDateorweekToDate, in queries and when authoring an axis. They usecurrentYear,currentQuarter,currentMonthorcurrentWeekonly when you ask for the entire period, including the days still to come. - The default comparison window is the previous window of the same length. A
last12Monthsaxis compares with the 12 months before it, not with the previous month. - To compare each row with the previous month, quarter or year, set
comparisonPeriodon the measure’speriodAxisbinding. The axis dimension rejectscomparisonPeriodandcomparisonOffset. The rowlevelmust be the same grain as the comparison or finer. - A comparison one step back at the row’s own level is not available on a current calendar window grouped by week, month or quarter. On
currentYear,currentQuarter,currentMonthandcurrentWeekaxes finer than the window but coarser than a day, the query engine compares every row with one constant, the last complete period before today. A measure withcomparisonPeriodequal to the axislevelthere is refused, and the editor shows Previous period disabled. Use the to-date window (yearToDate,quarterToDate,monthToDate),level: day, orcomparisonPeriod: year. - A measure can override the window with its own
periodAxisbinding (reference,period,level,periodEnd). Set alevelvalid for the override’s period; otherwise the axis level is inherited and can be refused as incompatible. - On a week, month or year axis, a bucket that straddles the window edge brings in rows from outside the window. The engine filters on the bucket’s start date, so a
yearToDateweek axis starts on the Monday before January 1. For exact boundaries, give the measure aperiodAxisoverride with the sameperiodat"level": "day"; it filters each row by its own date before grouping. See Weekly values without days outside the window. - If every measure overrides the window, nothing filters the axis itself. Keep one measure of type
currentwithout an override, and hide it withoutput. - A comparison wraps aggregate arithmetic, such as
SUM(revenue) / SUM(cost).NULLIFis not supported in stored measure expressions. A stored measure whose formula is arithmetic over other aggregate measures, such as{Sales} / {Orders}, can carry aperiodComparison: the references are replaced by their aggregates. That works only when each referenced measure is itself plain aggregate arithmetic, with no comparison, nested calculation, parameters or conditional. A measure that references a derived measure is refused with “Derived measure … may reference only aggregate measures”. In a query, wrapping an existing derived measure such as[Gross Sales] - [Discount Amount]can be refused: compare the base measures and combine the results, or store a measure whose formula is arithmetic over plain aggregate measures with theperiodComparisonon it. - A compared ratio is calculated for each period first, then compared. Growth is
(ratio_current - ratio_previous) / ABS(ratio_previous), not a ratio of growth rates. - Inside a query, references use the query’s own keys, such as
{ "dimension": "month" }, not layer names. The exception is a stored time axis the query does not select:periodComparisonandperiodAxismay name it by its layer name to compare one window with another across the whole answer, one row per segment instead of one per day. A key with the same name always wins. A stored comparison measure selected without its axis is the same window comparison, not a series of each row against the one before. Broken down by another grain of the axis’s own date field, such as months beside a month-on-month measure, its values mean nothing: each row’s dates fall in both windows or in one.resultNoticessays which case a query is in, inastrato_data_prepare_query,astrato_data_execute_queryand itsdryRun; select the axis to get the series. - Named periods are camelCase (
last90Days). Only measure filter conditions of typerelative_perioduse snake_case (last_90_days).
Last 7 days against the 7 days before
Section titled “Last 7 days against the 7 days before”{ "dimensions": [ { "key": "day", "periodAxis": { "level": "day", "period": "last7Days", "periodEnd": "today", "sources": [{ "reference": { "view": "Orders", "field": "Order Date" } }] } } ], "measures": [ { "key": "current", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "current", "reference": { "dimension": "day" } } }, { "key": "previous", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "value", "reference": { "dimension": "day" } } } ], "orderBy": [{ "reference": { "dimension": "day" }, "direction": "ascending" }]}Each day pairs with the day seven days earlier. For data that stops before today, use "periodEnd": "latest"; for a fixed reporting date, use "periodEnd": "fixed" with "periodEndDate". weekToDate compares the days of this week so far with the same days last week.
Monthly values with month-over-month change
Section titled “Monthly values with month-over-month change”Add one measure per result you want, changing type to value, diff or growth. growth is a ratio: 0.176 is +17.6%.
{ "dimensions": [ { "key": "month", "periodAxis": { "level": "month", "period": "last12Months", "periodEnd": "today", "sources": [{ "reference": { "view": "Orders", "field": "Order Date" } }] } } ], "measures": [ { "key": "revenue", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "current", "reference": { "dimension": "month" } } }, { "key": "momGrowth", "reference": { "measure": "Net Sales" }, "periodAxis": { "reference": { "dimension": "month" }, "comparisonPeriod": "month" }, "periodComparison": { "type": "growth", "reference": { "dimension": "month" } } } ], "orderBy": [{ "reference": { "dimension": "month" }, "direction": "ascending" }]}Several windows in one row
Section titled “Several windows in one row”Each measure overrides the window at day level, so each total stays inside its own week, month or year. The anchor measure follows the axis window and keeps the result to one row; output hides it.
{ "dimensions": [ { "key": "axis", "periodAxis": { "level": "year", "period": "currentYear", "periodEnd": "today", "sources": [{ "reference": { "view": "Orders", "field": "Order Date" } }] } } ], "measures": [ { "key": "revenueWTD", "reference": { "measure": "Net Sales" }, "periodAxis": { "reference": { "dimension": "axis" }, "period": "weekToDate", "level": "day" }, "periodComparison": { "type": "current", "reference": { "dimension": "axis" } } }, { "key": "revenueMTD", "reference": { "measure": "Net Sales" }, "periodAxis": { "reference": { "dimension": "axis" }, "period": "monthToDate", "level": "day" }, "periodComparison": { "type": "current", "reference": { "dimension": "axis" } } }, { "key": "revenueYTD", "reference": { "measure": "Net Sales" }, "periodAxis": { "reference": { "dimension": "axis" }, "period": "yearToDate", "level": "day" }, "periodComparison": { "type": "current", "reference": { "dimension": "axis" } } }, { "key": "anchor", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "current", "reference": { "dimension": "axis" } } } ], "output": [ { "reference": { "measure": "revenueWTD" } }, { "reference": { "measure": "revenueMTD" } }, { "reference": { "measure": "revenueYTD" } } ]}Weekly values without days outside the window
Section titled “Weekly values without days outside the window”The revenue measure overrides the window at day level, so each row counts only sales inside the year. The axis still groups by week, and the first week shows only the days from January 1. The anchor measure keeps the axis to its own window; output hides it.
{ "dimensions": [ { "key": "week", "periodAxis": { "level": "week", "period": "yearToDate", "periodEnd": "today", "sources": [{ "reference": { "view": "Orders", "field": "Order Date" } }] } } ], "measures": [ { "key": "revenue", "reference": { "measure": "Net Sales" }, "periodAxis": { "reference": { "dimension": "week" }, "period": "yearToDate", "level": "day" }, "periodComparison": { "type": "current", "reference": { "dimension": "week" } } }, { "key": "anchor", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "current", "reference": { "dimension": "week" } } } ], "orderBy": [{ "reference": { "dimension": "week" }, "direction": "ascending" }], "output": [{ "reference": { "dimension": "week" } }, { "reference": { "measure": "revenue" } }]}Period to date against the same point in the previous period
Section titled “Period to date against the same point in the previous period”The comparison window is cut at the same point, so the totals compare like for like: on October 1, monthToDate compares with September 1. Replace period with weekToDate, quarterToDate or yearToDate. Each total repeats on every row, so read it from any row. Remove advancedCalculation to get the daily values side by side.
{ "dimensions": [ { "key": "day", "periodAxis": { "level": "day", "period": "monthToDate", "periodEnd": "today", "sources": [{ "reference": { "view": "Orders", "field": "Order Date" } }] } } ], "measures": [ { "key": "currentTD", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "current", "reference": { "dimension": "day" } }, "advancedCalculation": { "total": { "aggregate": "SUM" } } }, { "key": "previousTD", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "value", "reference": { "dimension": "day" } }, "advancedCalculation": { "total": { "aggregate": "SUM" } } } ]}Daily values with a week-to-date total
Section titled “Daily values with a week-to-date total”The override limits revenueWTD to Monday through today, and total repeats that figure on every row. For an accumulating figure, see Running total and rank.
{ "dimensions": [ { "key": "day", "periodAxis": { "level": "day", "period": "last7Days", "periodEnd": "today", "sources": [{ "reference": { "view": "Orders", "field": "Order Date" } }] } } ], "measures": [ { "key": "revenue", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "current", "reference": { "dimension": "day" } } }, { "key": "revenueWTD", "reference": { "measure": "Net Sales" }, "periodAxis": { "reference": { "dimension": "day" }, "period": "weekToDate", "level": "day" }, "periodComparison": { "type": "current", "reference": { "dimension": "day" } }, "advancedCalculation": { "total": { "aggregate": "SUM" } } } ], "orderBy": [{ "reference": { "dimension": "day" }, "direction": "ascending" }]}Complete months only
Section titled “Complete months only”last12Months ends at the periodEnd date, so it includes the current partial month. To end at the last full month, use "periodEnd": "fixed" with the month’s last day. The date does not move, so update it each month.
"periodAxis": { "level": "month", "period": "last12Months", "periodEnd": "fixed", "periodEndDate": "2026-09-30", "sources": [{ "reference": { "view": "Orders", "field": "Order Date" } }]}Reading “this week”, “this month” and “versus last month”
Section titled “Reading “this week”, “this month” and “versus last month””Agents apply these defaults unless you say otherwise:
- “This week, month, quarter or year” means to date:
weekToDate,monthToDate,quarterToDateoryearToDatewith"periodEnd": "today". - “Versus last week, month or year” means the same point in the previous period, using
valueon the to-date axis, not the full previous period. Comparing a partial period with a full one overstates the decline. - The first and last buckets of a to-date axis are often partial, and their growth figures are misleading.
- Weeks start on Monday.
- Answers state the exact dates covered, such as Monday September 28 to Thursday October 1 against September 21 to 24.
What a comparison is about
Section titled “What a comparison is about”A comparison reads its own window, not the page around it, and its result depends on what the data holds on both sides. It can return a clean number that means nothing:
- With no date filter, a stored comparison still compares its own window. A
last12Monthsaxis with ayearbaseline compares those twelve months with the same twelve months a year earlier, whatever total sits beside the result. - A date filter narrows both sides, up to the window. Dates outside the axis window stay out, so
a filter longer than the window is cut to it. With
"periodEnd": "latest", the window ends on the last date the filter keeps. - A comparison window that reaches back past the first date in the data compares a whole period with part of one. The missing months are not counted, so the change looks far larger than it is.
- With no data at all on the comparison side,
valueandgrowthare empty, not zero. An empty result means there is no comparison. It does not mean nothing changed.
To see which of these you have, read both sides beside the change. A stored comparison measure takes no second comparison, so send the plain measure under it three times, on the same axis and baseline, with the same filters as the page:
{ "dimensions": [], "measures": [ { "key": "current", "reference": { "measure": "Net Sales" }, "periodAxis": { "reference": { "dimension": "Sales timeline" }, "comparisonPeriod": "year" }, "periodComparison": { "type": "current", "reference": { "dimension": "Sales timeline" } } }, { "key": "prior", "reference": { "measure": "Net Sales" }, "periodAxis": { "reference": { "dimension": "Sales timeline" }, "comparisonPeriod": "year" }, "periodComparison": { "type": "value", "reference": { "dimension": "Sales timeline" } } }, { "key": "change", "reference": { "measure": "Net Sales" }, "periodAxis": { "reference": { "dimension": "Sales timeline" }, "comparisonPeriod": "year" }, "periodComparison": { "type": "growth", "reference": { "dimension": "Sales timeline" } } } ]}current must equal the figure the change is shown beside, and prior must cover a complete
period. For what to show when they do not, see
Show a change only when it means something.
Rolling average, window total and share of a group
Section titled “Rolling average, window total and share of a group”These calculations run over the answer’s rows in question order, so order by the date dimension. A moving window counts rows, not calendar months. A measure-level window with nestedCalculation AVG over the same month dimension is not a rolling average: each month averages itself.
Add this measure to the measures array of a query that defines the month axis, as in the monthly example above:
{ "key": "rolling6", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "current", "reference": { "dimension": "month" } }, "advancedCalculation": { "movingCalculation": { "aggregate": "AVG", "windowBegin": -5, "windowEnd": 0 } }}Use "advancedCalculation": { "total": { "aggregate": "SUM" } } to repeat the window total on every row, and "advancedCalculation": { "compareToTotal": { "aggregate": "SUM", "comparison": "ratio", "partitionBy": [{ "reference": { "dimension": "region" } }] } } to give each customer’s share of its region, with both region and customer as dimensions. The answer needs a finer grain than the partition; with only region, each row is its own group total.
Each member compared between two periods
Section titled “Each member compared between two periods”Add a dimension beside the axis to compare every member (campaign, product, region) between two periods in one query. The engine pairs each member’s current row with its own comparison row. A member with no data in the comparison period gets empty value, diff and growth. Ordering by the growth measure answers “which improved most”.
To name two specific months, use "period": "currentMonth" with "periodEnd": "fixed" on the last day of the later month; the default comparison is the previous month. currentQuarter and currentYear work the same way.
{ "dimensions": [ { "key": "region", "reference": { "view": "Customers", "field": "Region" } }, { "key": "month", "periodAxis": { "level": "month", "period": "currentMonth", "periodEnd": "fixed", "periodEndDate": "2026-09-30", "sources": [{ "reference": { "view": "Orders", "field": "Order Date" } }] } } ], "measures": [ { "key": "september", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "current", "reference": { "dimension": "month" } } }, { "key": "august", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "value", "reference": { "dimension": "month" } } }, { "key": "change", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "diff", "reference": { "dimension": "month" } } }, { "key": "growth", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "growth", "reference": { "dimension": "month" } } } ], "orderBy": [{ "reference": { "measure": "growth" }, "direction": "descending" }]}To limit the answer to members active in both periods, define “active” on the selected measure in each period (spend, revenue, orders) and state it. An empty value means the member has no data in that period, not that it was inactive; a positive-activity criterion also excludes zero values, which an empty-value filter keeps. Growth can also be empty when the comparison value is zero. Exclude rows with an empty comparison value as a missing-data filter when reading the result, then apply the activity criterion.
Running total and rank
Section titled “Running total and rank”advancedCalculation takes one of movingCalculation, runningTotal, runningRate, rank or interRecord, and optionally total or compareToTotal, ordered and partitioned by the question’s own dimension keys. runningTotal and runningRate require aggregate, orderBy and partitionBy ([] for none) and restart for each partitionBy member. A weekToDate axis spans one week, so a running total ordered by day is a week-to-date running sum:
{ "dimensions": [ { "key": "day", "periodAxis": { "level": "day", "period": "weekToDate", "periodEnd": "today", "sources": [{ "reference": { "view": "Orders", "field": "Order Date" } }] } } ], "measures": [ { "key": "runningRevenue", "reference": { "measure": "Net Sales" }, "periodComparison": { "type": "current", "reference": { "dimension": "day" } }, "advancedCalculation": { "runningTotal": { "aggregate": "SUM", "orderBy": [{ "reference": { "dimension": "day" }, "direction": "ascending" }], "partitionBy": [] } } } ], "orderBy": [{ "reference": { "dimension": "day" }, "direction": "ascending" }]}"rank": { "direction": "descending", "partitionBy": [{ "reference": { "dimension": "region" } }] } ranks each customer within its region.
Stored measures
Section titled “Stored measures”Month-over-month growth on a stored measure uses baseline.grain in definition.periodComparison:
{ "type": "growth", "timeAxis": "Time Axis", "baseline": { "grain": "month" } }The last 90 days against the 90 days before, whatever the axis window:
{ "type": "current", "timeAxis": "Order Date (Day)", "window": { "period": "last90Days", "level": "day" }}window is an object; a string is rejected.
One definition, two owners
Section titled “One definition, two owners”Use a named global dimension when several questions or measures should share the same timeline:
dimensions: Sales timeline: kind: periodAxis resultType: date periodAxis: sources: - reference: { view: Sales, field: Date } period: currentYear level: monthperiod selects the current calendar year. level produces monthly buckets. A measure binding with comparisonPeriod: year compares each bucket with the corresponding bucket one year earlier. Omitting resultType on a period-axis dimension normalizes it to date.
A business question can reuse that dimension under a local key:
businessQuestions: Monthly sales: dimensions: - key: month reference: { dimension: Sales timeline } measures: - key: sales reference: { measure: Sales } - key: growth reference: { measure: Sales } periodAxis: reference: { dimension: month } comparisonPeriod: year periodComparison: type: growth reference: { dimension: month }month names the selection inside this question. It does not rename Sales timeline or change its grouping. The comparison references the local key month. When dimensions are keyed, select a global dimension under a local key before binding a calculation to it.
For a timeline owned only by this question, embed the identical block directly:
businessQuestions: Monthly sales: dimensions: - key: month periodAxis: sources: - reference: { view: Sales, field: Date } period: currentYear level: month measures: - key: sales reference: { measure: Sales } - key: growth reference: { measure: Sales } periodAxis: reference: { dimension: month } comparisonPeriod: year periodComparison: type: growth reference: { dimension: month } orderBy: - reference: { dimension: month } direction: ascendingThe local dimension has no kind or resultType wrapper. It belongs to this question and is not added to the global dimensions list. Questions with unkeyed dimensions remain supported. Keyed dimensions can also reference a field directly with reference: { view: Sales, field: Date }; that selects the field without creating a period axis.
Relative date and relative date range
Section titled “Relative date and relative date range”offset, from, and to must be whole numbers within JavaScript’s safe-integer range
(−9,007,199,254,740,991 through 9,007,199,254,740,991). Values outside that range are rejected.
A relative date selects one calendar unit at an offset from the current unit. This global dimension selects yesterday:
dimensions: Yesterday: kind: periodAxis periodAxis: sources: - reference: { view: Sales, field: Date } period: { kind: relativeValue, unit: day, offset: -1 } level: dayA relative range includes every calendar unit from from through to. This BQ selects the current month and the preceding eleven months:
businessQuestions: Rolling monthly sales: dimensions: - key: month periodAxis: sources: - reference: { view: Sales, field: Date } period: { kind: relativeRange, unit: month, from: -11, to: 0 } level: month measures: - key: growth reference: { measure: Sales } periodAxis: reference: { dimension: month } comparisonPeriod: year periodComparison: type: growth reference: { dimension: month }Both forms work in either owner: copy the complete periodAxis block between them. A range ending at 0 includes the current calendar unit; it does not mean “to the current instant.” Use a named to-date period for that intent. Offsets must be integers, and from must be less than or equal to to.
Sources and valid settings
Section titled “Sources and valid settings”sources contains one or more date or timestamp fields, with at most one source from each view. A source can instead reference an ordinary, untransformed field dimension:
periodAxis: sources: - reference: { dimension: Sales date } - reference: { view: Returns, field: Returned date } period: currentYear level: monthA source dimension must resolve to a date or timestamp field. A bucket, hierarchy, another period axis, or a dimension with a date transformation is not a valid source.
The date a period is read as of
Section titled “The date a period is read as of”A period is read as of today unless its periodEnd says otherwise. There are four ends:
periodEnd |
Reads the period as of | Applies to |
|---|---|---|
today (omitted) |
today | every period |
yesterday |
the last complete day | to-date and trailing windows, and today |
latest |
the latest date in the data, resolved from the axis’s date field in SQL | every named period, calendar windows included |
fixed |
periodEndDate, a YYYY-MM-DD date you choose |
every period, named and relative |
The default today applies to every query, including caller-defined HTTP and MCP
queries, so to-date totals stay within their daily cutoff even when the output is
grouped by week, month or year. A partial measure
binding with no end still inherits its axis’s end. currentWeek, currentMonth,
currentQuarter and currentYear continue to select complete calendar periods,
including future facts within those periods.
Latest is for data that does not run up to today: a sample, a historical extract, or a feed that stopped. On the clock, every relative period of such data is empty; anchored at the latest date, “current year” is the year that date falls in and “last 30 days” are the 30 days up to it:
dimensions: Order year: kind: periodAxis periodAxis: sources: - reference: { view: Sales, field: Date } period: currentYear level: month periodEnd: latestFixed reads every period as of one date, for a report that must show the same numbers whenever it is opened:
dimensions: Year to date as of August: kind: periodAxis periodAxis: sources: - reference: { view: Sales, field: Date } period: yearToDate level: month periodEnd: fixed periodEndDate: '2021-08-01'Yesterday closes a window that runs up to the present on the last complete day:
dimensions: Trailing month: kind: periodAxis periodAxis: sources: - reference: { view: Sales, field: Date } period: last30Days level: day periodEnd: yesterdayAn end is accepted only where it applies: yesterday on a calendar or boundary window, and latest on a relative offset, are refused rather than silently ignored. periodEndDate is required with fixed and refused with any other end. The cutoff applies before aggregation at any allowed grouping, so you can group month-to-date by month while ending yesterday.
In the dimension editors this is the Period as of setting, which offers only the ends the chosen period takes, and a date picker for Fixed date. A time intelligence measure offers the same setting for the window in effect, its own or the inherited one: inheriting the axis’s end is stored as nothing, and a different end (or the same fixed end at a different date) is stored as the measure’s own periodAxis.periodEnd and periodAxis.periodEndDate, a partial override of the axis.
The supported named periods are:
| Family | period values |
Allowed level |
|---|---|---|
| Year | currentYear, previousYear, yearToDate, previousYearToDate, extractYearToDate |
year, quarter, month, week, day |
| Quarter | currentQuarter, previousQuarter, quarterToDate, previousQuarterToDate |
quarter, month, week, day |
| Month | currentMonth, previousMonth, monthToDate, previousMonthToDate, extractMonthToDate |
month, week, day |
| Week | currentWeek, previousWeek, weekToDate, previousWeekToDate |
week, day |
| Twelve months | last12Months |
month |
| Days | last90Days, last30Days, last7Days, today, yesterday |
day |
| Boundaries | beginningOfYear, beginningOfPreviousYear, beginningOfQuarter, beginningOfPreviousQuarter, beginningOfMonth, beginningOfPreviousMonth, beginningOfWeek, beginningOfPreviousWeek, endOfYear, endOfQuarter, endOfMonth, endOfWeek |
day |
Relative forms accept year, quarter, month, week, and day as unit. Their level must match unit. For finer grouping, use a supported named period: for example, period: previousMonth with level: day selects the full previous month in daily buckets. minimumDate and maximumDate remain filter-only selectors.
comparisonPeriod accepts the same five grains. The grouping level must be the same grain or finer than the comparison baseline. For example, level: month supports comparison by month, quarter, or year. The baseline belongs to the measure binding, never to the axis definition, and a measure that stores none follows its axis: a named period keeps its built-in previous interval, a relative period steps by its unit — so changing the axis carries through to every measure that does not override it.
Period over period is authored on time intelligence measures — the Time intelligence measure entry when creating a measure: a formula over other measures whose point is the comparison. A time intelligence measure is recognised by the comparison it carries; nothing else is stored. In its editor these are the Compare to and Offset settings, shown for every result except Current: Previous period, or the same period in the previous year, quarter or month. For a trailing window (last 7, 30 or 90 days, last 12 months, today, yesterday) Previous period is the window’s own previous interval and stores no comparisonPeriod. For a calendar window (current or to-date) it steps each row back one grouping level — month over month for Year to date by month, quarter over quarter by quarter — and stores the grouping level as comparisonPeriod. comparisonOffset on the binding, beside the baseline it steps, is the number of those steps to take — negative looks back, positive ahead — and defaults to -1, which is stored as an omission. For example:
measures: Two years back: resultType: float expression: '{m1}' m1: { aggregate: SUM, arguments: [{ reference: { view: Sales, field: Amount } }] } periodAxis: reference: { dimension: Sales timeline } comparisonPeriod: year comparisonOffset: -2 periodComparison: type: growth reference: { dimension: Sales timeline }Comparison alignment and scope
Section titled “Comparison alignment and scope”Use these settings on periodComparison to control alignment and scope:
alignment—calendar(the default, stored as nothing) lines the compared period up on the same calendar date;weekdaylines it up on the same weekday.additionalDimensions— the comparison’s time-axis scope, which lets a KPI compare on an axis that is not among its output dimensions. To aggregate at an intermediate grain, usenestedCalculationseparately. Declare the stored axis by reference alone (- reference: { dimension: Sales timeline }); add aperiodorlevelto the entry to use a different window or grouping over the same date fields.
Both settings are preserved through import and export.
Measure overrides and reduction
Section titled “Measure overrides and reduction”Global measure references use global dimension names. A binding can name the comparison baseline for this measure while other measures continue to inherit the axis. A binding with a period, level or periodEnd of its own is a time axis override. Omitted settings inherit from the referenced axis: a period end alone moves the cutoff and keeps the axis window; a window replaces the inherited window. Choose Inherit from date field to use the axis’s settings.
In a business question or query with other measures, a measure selection’s override applies to that measure only. The axis keeps its own window and every other measure is answered over it; the overridden measure is empty on the axis rows outside its window. Last 7 days by day beside a week-to-date measure returns seven rows, with the week-to-date measure empty on the days before Monday. Two selections may override with different windows. A selection with an override and no other measures is answered over its own window. A selection with an override and no comparison behaves as a current comparison on its axis.
Two kinds of override still set the window of the whole answer they are selected in:
- An override on a selection with an
advancedCalculation. - A stored measure whose binding carries a window and no comparison. Give it
periodComparison: { type: current }on the same axis to scope the window to the measure.
measures: Sales growth: resultType: float expression: '{m1}' m1: aggregate: SUM arguments: - reference: { view: Sales, field: Amount } periodComparison: type: growth reference: { dimension: Sales timeline } periodAxis: reference: { dimension: Sales timeline } comparisonPeriod: quarterComparison types are current (the current period’s own value), value (prior value), diff (current minus prior), ratio (current divided by prior), and growth ((current minus prior) divided by the absolute prior value). Format growth as a percentage when that is how you want it displayed.
nestedCalculation calculates the formula at each axis bucket and then reduces those values. Its aggregate is SUM, AVG, MIN, or MAX; dimensions contains exactly one period-axis reference. A comparison compares the reduced results. It is an explicit business definition — sales per order as a ratio of monthly totals, say — and the editor never adds one: a comparison saved from the measure editor stands on its own, whichever result it shows, and the formula is recomputed over each complete period. A stored reduction is kept as stored, on a measure with or without a comparison.
A comparison is computed grouped by its axis, with or without a reduction, so a measure’s SQL preview asks for the axis.
businessQuestions: Average monthly sales growth: dimensions: - key: month reference: { dimension: Sales timeline } measures: - key: growth reference: { measure: Sales } periodAxis: reference: { dimension: month } comparisonPeriod: year nestedCalculation: aggregate: AVG dimensions: - reference: { dimension: month } periodComparison: type: growth reference: { dimension: month }The outer periodAxis belongs to the result calculation. The inner nestedCalculation.periodAxis belongs to the calculation being reduced. Both inherit omitted settings from the referenced axis, and all references in one calculation must identify that same axis. The inner binding stays separate when saved, reloaded and compared. A global measure uses these same three blocks with a global dimension name instead of month.
comparisonPeriod belongs to an enabled comparison. The query engine does not accept it on a standalone axis binding or as a separate inner offset in nestedCalculation.periodAxis. Such saved settings remain readable, but must be removed or changed before publishing or executing the measure; they are never silently translated into another calculation.
Use it in the editor
Section titled “Use it in the editor”- In Dimensions, create a Time intelligence axis. Select its date sources, period and grouping.
- Open a measure and expand Period over period. Enable the comparison, then choose Date field, Period, and Show as. Use Show more… for additional named periods. Grouping follows the selected period and date field; saved grouping overrides, custom periods and explicit reductions are preserved. The form does not add a reduction. A new comparison uses the effective grouping level as its offset. If a new period conflicts with a saved offset, choose another period or use the offered offset repair before saving. Other offsets remain editable through
periodAxis.comparisonPeriodin the document. - In a named business question, edit Named dimensions and measures, apply the YAML selections, then update the question. The document editor can also author the complete examples above, including separate inner bindings.
- Run a named BQ in Data Explorer to open its result table. This executes the complete saved definition against the published layer. Named BQs use this table rather than an interactive chart preview. The table labels its columns with the local keys and reports when the result was bounded.
- Use version compare to inspect source, period, grouping, comparison and nested-calculation changes.
Earlier documents using kind: timeAxis, selector, dateLevel, timeAxis measure bindings, or nested are migrated when loaded. The canonical YAML uses the names shown here.