Time Intelligence & Calculation Groups
Master time intelligence DAX functions β year-to-date, same period last year, semi-additive measures β and learn how calculation groups reduce measure duplication.
Comparing across time
Think about your bank account. You donβt just want to know your balance today β you want to know if itβs higher than last month, how much youβve spent year-to-date, and whether youβre on track compared to the same time last year.
Time intelligence DAX functions let you ask these same questions about your business data: year-to-date revenue, this quarter vs last quarter, running totals over months. They all require a proper date table (covered in the Date Tables module).
Essential time intelligence functions
Year-to-date
YTD Revenue =
TOTALYTD(
SUM(Sales[Revenue]),
'Date'[Date]
)
Or equivalently using CALCULATE + DATESYTD:
YTD Revenue =
CALCULATE(
SUM(Sales[Revenue]),
DATESYTD('Date'[Date])
)
Riley at Coastal Fresh (π) puts this in a matrix with months as rows. In March, it shows Jan + Feb + Mar cumulative revenue. In June, it shows Jan through June.
Same period last year
Revenue Last Year =
CALCULATE(
SUM(Sales[Revenue]),
SAMEPERIODLASTYEAR('Date'[Date])
)
YoY Change % =
VAR Current = SUM(Sales[Revenue])
VAR LastYear = CALCULATE(SUM(Sales[Revenue]), SAMEPERIODLASTYEAR('Date'[Date]))
RETURN
DIVIDE(Current - LastYear, LastYear)
Kenji at Apex Manufacturing (π) uses YoY Change to compare this Aprilβs production to last Aprilβs.
DATEADD: flexible period shifting
Revenue 3 Months Ago =
CALCULATE(
SUM(Sales[Revenue]),
DATEADD('Date'[Date], -3, MONTH)
)
DATEADD is more flexible than SAMEPERIODLASTYEAR β you can shift by any number of days, months, quarters, or years.
Common time intelligence functions
| Function | What It Does |
|---|---|
TOTALYTD(measure, date) | Year-to-date accumulation |
TOTALQTD(measure, date) | Quarter-to-date |
TOTALMTD(measure, date) | Month-to-date |
SAMEPERIODLASTYEAR(date) | Shifts dates back one year |
DATEADD(date, intervals, type) | Shifts dates by any amount |
PREVIOUSMONTH(date) | Returns dates from the previous month |
PREVIOUSQUARTER(date) | Returns dates from the previous quarter |
DATESYTD(date) | Returns year-to-date dates |
DATESINPERIOD(date, start, intervals, type) | Returns a custom rolling window |
Exam tip: time intelligence requirements
Time intelligence functions work best with:
- A marked date table (Table tools β Mark as date table)
- Contiguous dates β no gaps in the date column
- The date column should be Date or Date/Time data type
If time intelligence returns unexpected results, check these requirements first. Power BIβs auto date/time feature provides basic time intelligence without a custom date table, but a dedicated date table gives you full control and is the exam-expected approach.
Semi-additive measures
Some values shouldnβt be summed across time. Kenji tracks inventory levels β if he has 500 units on Monday, 480 on Tuesday, and 510 on Wednesday, the weekly inventory isnβt 1,490 (the sum). Itβs 510 (the latest value).
Current Inventory =
CALCULATE(
SUM(Inventory[Quantity]),
LASTDATE('Date'[Date])
)
Or using CLOSINGBALANCEMONTH for month-end snapshots:
Month End Balance =
CLOSINGBALANCEMONTH(
SUM(Accounts[Balance]),
'Date'[Date]
)
Semi-additive examples: inventory counts, account balances, headcount, stock prices β anything where summing across time gives a meaningless number.
| Measure Type | Sum Across Time? | Example | DAX Approach |
|---|---|---|---|
| Additive | Yes β | Revenue, units sold, hours worked | SUM() works fine |
| Semi-additive | No β | Inventory, headcount, account balance | Use LASTDATE, CLOSINGBALANCEMONTH, or LASTNONBLANK |
| Non-additive | No β | Ratios, percentages, averages | Calculate from additive components |
Calculation groups
Calculation groups let you apply time intelligence (or any transformation) to multiple measures without duplicating code.
Without calculation groups, Nadia at Prism Agency (π) would need:
- Revenue YTD, Clicks YTD, Impressions YTD, Spend YTD
- Revenue LY, Clicks LY, Impressions LY, Spend LY
- Revenue YoY%, Clicks YoY%, Impressions YoY%, Spend YoY%
Thatβs 12 measures for 4 base measures Γ 3 time views. With 10 base measures, it becomes 30 measures.
Calculation groups define the time transformation ONCE:
| Calculation Item | Logic |
|---|---|
| Current | SELECTEDMEASURE() (no change) |
| YTD | CALCULATE(SELECTEDMEASURE(), DATESYTD(βDateβ[Date])) |
| Prior Year | CALCULATE(SELECTEDMEASURE(), SAMEPERIODLASTYEAR(βDateβ[Date])) |
| YoY % | (Current - Prior Year) / Prior Year |
Now any measure can use these items: drop the calculation group on a visual, and every measure gets YTD, Prior Year, and YoY% automatically.
How to create calculation groups
Calculation groups are created in Model view β New calculation group (or using external tools like Tabular Editor).
Each calculation group:
- Has a name (e.g., βTime Intelligenceβ)
- Contains calculation items (e.g., βYTDβ, βPrior Yearβ)
- Uses
SELECTEDMEASURE()to reference whatever measure is being modified - Appears as a column in the Fields pane that can be placed on visuals
On the exam, know that calculation groups reduce measure proliferation β one group with 4 items applied to 10 base measures replaces 40 individual measures.
Knowledge check
Kenji tracks factory inventory. He uses SUM(Inventory[Quantity]) and sees that the monthly total is 15,000 β but the actual inventory is 500 units. What went wrong?
Which DAX function shifts dates by a flexible number of periods (days, months, quarters, or years)?
Next up: Model Performance Optimisation β find and fix slow queries with Performance Analyzer and DAX query view.