Power BI How-To / DAX Patterns
How to Use Power BI Time Intelligence DAX Functions
Power BI time intelligence DAX functions — TOTALYTD, SAMEPERIODLASTYEAR, DATEADD, and friends — turn one base measure into year-to-date, prior-year, and period-shifted comparisons in a single line each. This guide covers the date table requirements they all share, the core patterns with worked code, and a comparison table of when to use which function.
What are time intelligence functions in DAX?
Time intelligence functions are a family of DAX functions that shift or extend the date filter on a measure, so one base measure can report year-to-date, the same period last year, or a rolling window without duplicating logic. The big four in practice are TOTALYTD, DATESYTD, SAMEPERIODLASTYEAR, and DATEADD.
They all follow the same idea: instead of changing what you sum, you change which dates the sum sees. Start with a base measure like Total Sales = SUM(Sales[Amount]), then wrap it so the date filter is rewritten — extended back to January 1 for YTD, or slid back twelve months for a prior-year comparison. If filter context is still new to you, read what DAX is (measures vs calculated columns) first; every function on this page is just a shortcut for rewriting filter context on a date column. Microsoft’s time intelligence function reference (opens in new tab) lists the full family and current syntax.
What does every time intelligence function require from your date table?
Every time intelligence function assumes a dedicated Date table that is continuous (no missing days), covers whole years, uses a true date data type, is related to your fact table, and is set with ‘Mark as Date Table’. Miss any of those and functions return blanks, wrong shifts, or totals that silently repeat.
This is the single most common failure point. Dates taken straight from the fact table usually have gaps — no sales on a Sunday means no row for that date — and DATEADD in particular refuses to shift over a calendar with holes. Build a Date table with CALENDAR() or CALENDARAUTO() (or reuse a shared one), make sure it spans complete years, relate it to the fact table’s date key, and mark it. Do it once and every function below simply works.
How do TOTALYTD and DATESYTD build year-to-date measures?
TOTALYTD is the one-line version: Sales YTD = TOTALYTD( [Total Sales], 'Date'[Date] ) accumulates from January 1 through the current date and resets each year. DATESYTD does the same date-shifting inside CALCULATE, which is the form you want when combining YTD with other filter changes.
The CALCULATE form is Sales YTD = CALCULATE( [Total Sales], DATESYTD( 'Date'[Date] ) ) — identical output, more room to grow. Both accept an optional fiscal year-end, so TOTALYTD( [Total Sales], 'Date'[Date], "6/30" ) gives a July–June fiscal year. Under the hood this is a running total that resets every January; if you want to understand or hand-build that mechanic, see our guide to running totals in Power BI with DAX, which walks the CALCULATE + FILTER + ALL pattern these shortcuts wrap.
What is the difference between SAMEPERIODLASTYEAR and DATEADD?
SAMEPERIODLASTYEAR shifts the current date range back exactly one year — nothing else. DATEADD is the general tool: it shifts by any number of days, months, quarters, or years, so it covers month-over-month and rolling comparisons too. SAMEPERIODLASTYEAR is literally DATEADD with a fixed one-year shift.
A prior-year measure looks like Sales PY = CALCULATE( [Total Sales], SAMEPERIODLASTYEAR( 'Date'[Date] ) ); the equivalent DATEADD form is CALCULATE( [Total Sales], DATEADD( 'Date'[Date], -1, YEAR ) ), and swapping the arguments to -1, MONTH gives month-over-month. With [Total Sales] and [Sales PY] in place, growth is just subtraction and DIVIDE. The table below summarizes when each function is the right pick.
| Function | What it does | Typical use | Watch out for |
|---|---|---|---|
| TOTALYTD | Accumulates a measure from the start of the year to the current date | One-line YTD sales, costs, or headcount | Custom fiscal years need the year-end argument |
| DATESYTD | Returns the year-to-date set of dates for use inside CALCULATE | YTD combined with other filters in one CALCULATE | Must filter the Date table’s date column, not the fact table’s |
| SAMEPERIODLASTYEAR | Shifts the current date range back exactly one year | Prior-year comparisons and year-over-year growth | Blank results usually mean the date table is not marked |
| DATEADD | Shifts the date range by N days, months, quarters, or years | Month-over-month, quarter-over-quarter, custom shifts | Fails on non-contiguous calendars — needs a gap-free Date table |
| PARALLELPERIOD | Returns the whole parallel period rather than a matching partial range | Comparing against a full prior month or quarter | Ignores partial periods — different answer than DATEADD mid-month |
Why do time intelligence measures return blank or wrong numbers?
Almost every broken time intelligence measure traces to the calendar, not the formula: the Date table is missing or unmarked, the calendar has gaps or partial years, the function filters the fact table’s date column instead of the Date table’s, or an inactive relationship never gets activated. Check those four before rewriting anything.
- Is there a dedicated Date table with ‘Mark as Date Table’ set?
- Is the calendar continuous and does it cover complete years?
- Does the function reference
'Date'[Date]— the Date table’s column — not a fact-table date? - If the model has multiple date roles (order date, ship date), is USERELATIONSHIP activating the right one?
- Is the visual’s axis built from the Date table, so the shift and the axis agree?
If the measures are right but the model still fights you — multiple calendars, role-playing dates, slow year-over-year visuals — that is model design work, and our data modeling and DAX service covers exactly that: we scope the fix, quote hours before working, and you approve before anything is deducted.
Wrestling with YTD or prior-year measures that won’t behave?
Most time intelligence bugs are a short, well-scoped fix once the date table is right. Bring your model to a free demo — we scope it, you approve, and senior prepaid hours that never expire cover the work.
FAQ
Frequently asked questions
Rarely, and never reliably. TOTALYTD, DATESYTD, SAMEPERIODLASTYEAR, and DATEADD all assume a continuous, marked Date table related to your fact table. Without one you get blanks, repeated totals, or shifts that land on the wrong dates. Building and marking a proper Date table fixes most time intelligence bugs before you touch a formula.
They produce the same year-to-date result. TOTALYTD is a self-contained one-liner that wraps the measure for you; DATESYTD returns the year-to-date set of dates for use inside CALCULATE, which gives you room to combine YTD with other filter changes in the same expression. Start with TOTALYTD; switch to DATESYTD when measures get layered.
DATEADD shifts a range of dates, so it needs a calendar with no gaps to land on. If your date column comes from the fact table, days with no transactions are missing and the shift fails. The fix is a dedicated Date table built with CALENDAR or CALENDARAUTO, covering complete years, related to the fact table, and marked as a date table.
Pass the fiscal year-end as the optional argument: TOTALYTD with a year-end of "6/30" accumulates July through June, and DATESYTD accepts the same argument inside CALCULATE. Keep the fiscal year label as a column on your Date table too, so axes and slicers group dates the same way the measures do.
Try us risk-free for 4 hours
If you’re unhappy within the first 4 hours of your block, we’ll refund you in full — no questions asked. Hours are deducted only for work you’ve reviewed and approved, and they never expire.
Book a free demo
Get senior Power BI help, on demand
Tell us the task. We scope it, you approve, and a senior consultant delivers — typically in 3–5 business days. Prepaid hours that never expire.
- Prepaid hours from $100/hour — and they never expire
- Senior-led delivery — 20+ years on the Microsoft platform
- Typical 3–5 business day turnaround
- Full refund if you’re unhappy in your first 4 hours
The fastest way to reach us is the form — tell us the task and we'll reply within one business day.