Wicked Smart Data
LearnArticlesAbout
Sign InSign Up
LearnArticlesAboutContact
Sign InSign Up
Wicked Smart Data

The go-to platform for professionals who want to master data, automation, and AI — from Excel fundamentals to cutting-edge machine learning.

Platform

  • Learning Paths
  • Articles
  • About
  • Contact

Connect

  • Contact Us
  • RSS Feed

© 2026 Wicked Smart Data. All rights reserved.

Privacy PolicyTerms of Service
All Articles
Mastering Time Intelligence in Power BI: Building YTD, MTD, and Period-over-Period DAX Measures

Mastering Time Intelligence in Power BI: Building YTD, MTD, and Period-over-Period DAX Measures

Power BI⚡ Practitioner19 min readJul 10, 2026Updated Jul 10, 2026
Table of Contents
  • Introduction
  • Prerequisites
  • Why Time Intelligence Requires a Dedicated Date Table
  • Building Your Date Table
  • Understanding How DAX Time Intelligence Functions Actually Work
  • Building Your Core Measures
  • Year-to-Date Revenue
  • Month-to-Date Revenue
  • Quarter-to-Date Revenue
  • Fiscal Year-to-Date
  • Period-over-Period Comparisons: The Real Power
  • Prior Year Revenue (Same Period)
  • Year-over-Year Variance

Mastering Time Intelligence in Power BI: Building YTD, MTD, and Period-over-Period DAX Measures

Introduction

You've built your Power BI report, your sales numbers look great on a bar chart, and your stakeholder leans across the table and asks: "Okay, but how does this compare to last year at the same point?" You freeze. Your report shows what happened, but it can't answer how things are trending — and that's exactly the gap that time intelligence fills.

Time intelligence is the practice of writing DAX measures that understand how time flows: what "year to date" means on a rolling basis, how this month compares to the same month last year, and why February needs special treatment. These are the measures that transform a static snapshot into a living analysis. They're also the measures that most Power BI practitioners get subtly wrong — not in ways that cause errors, but in ways that silently produce misleading numbers.

By the end of this lesson, you'll have a working time intelligence layer that you can drop into any production report. You'll understand not just the syntax, but the mechanism — why DAX time intelligence functions work the way they do, what the date table requirement actually means, and how to debug the inevitable moment when your YTD measure returns blank.

What you'll learn:

  • How to build and configure a proper date table that enables time intelligence functions
  • Writing correct, production-ready YTD and MTD measures using both built-in and custom approaches
  • Building period-over-period comparisons (vs. prior year, vs. prior month) and calculating variance
  • Handling partial periods and fiscal calendars with confidence
  • Debugging common time intelligence failures and understanding why they happen

Prerequisites

You should be comfortable writing basic DAX measures — SUM, CALCULATE, FILTER — and you should understand the difference between a measure and a calculated column. You should also have a working data model with a fact table containing a date column (or date key). If you've worked through the fundamentals of DAX and the Power BI data model, you're in the right place.


Why Time Intelligence Requires a Dedicated Date Table

Before we write a single measure, we need to talk about the date table — because this is the root cause of 80% of broken time intelligence measures.

DAX's built-in time intelligence functions like TOTALYTD, SAMEPERIODLASTYEAR, and DATEADD don't operate on the date column in your fact table. They operate on a marked date table — a separate, complete, contiguous table of dates with one row per day that covers the full range of your data. When you use DATESYTD inside CALCULATE, DAX uses this table to understand how calendar periods relate to each other.

Without a proper date table, DAX can't know that February 28 is the last day of February in a non-leap year, that Q3 starts in July, or that the week containing January 1 might belong to the previous year's ISO week. You're not just providing data — you're providing a calendar model.

Building Your Date Table

Here's a complete date table in DAX that you can paste directly into Power BI as a calculated table. We'll use a realistic range and include columns you'll actually need:

Date =
VAR StartDate = DATE(2020, 1, 1)
VAR EndDate = DATE(2025, 12, 31)
RETURN
ADDCOLUMNS(
    CALENDAR(StartDate, EndDate),
    "Year",             YEAR([Date]),
    "Month Number",     MONTH([Date]),
    "Month Name",       FORMAT([Date], "MMMM"),
    "Month Short",      FORMAT([Date], "MMM"),
    "Quarter Number",   QUARTER([Date]),
    "Quarter",          "Q" & QUARTER([Date]),
    "Year-Quarter",     YEAR([Date]) & " Q" & QUARTER([Date]),
    "Year-Month",       FORMAT([Date], "YYYY-MM"),
    "Day of Week",      WEEKDAY([Date], 2),
    "Day Name",         FORMAT([Date], "dddd"),
    "Week Number",      WEEKNUM([Date], 2),
    "Is Weekend",       IF(WEEKDAY([Date], 2) >= 6, TRUE(), FALSE()),
    "Is Current Month", IF(
                            YEAR([Date]) = YEAR(TODAY()) && MONTH([Date]) = MONTH(TODAY()),
                            TRUE(), FALSE()
                        ),
    "Fiscal Year",      IF(MONTH([Date]) >= 7,
                            "FY" & YEAR([Date]) + 1,
                            "FY" & YEAR([Date])
                        ),
    "Fiscal Quarter",   SWITCH(
                            TRUE(),
                            MONTH([Date]) IN {7,8,9},   "FQ1",
                            MONTH([Date]) IN {10,11,12}, "FQ2",
                            MONTH([Date]) IN {1,2,3},   "FQ3",
                            MONTH([Date]) IN {4,5,6},   "FQ4"
                        )
)

Tip: If your fiscal year starts in a month other than July, change the 7 in the Fiscal Year column to your fiscal year start month. For April starts, use 4. Everything downstream will update automatically.

After creating this table, you need to do two things: mark it as a Date Table and create a relationship.

To mark it as a date table, select the table in the Data pane, go to Table Tools in the ribbon, and click "Mark as date table." Choose the Date column as the date column. This step is what tells DAX's time intelligence engine which column represents the calendar.

Then create a relationship from Date[Date] to your fact table's date column (e.g., Sales[Order Date]). Make it a many-to-one relationship from Sales to Date, with single-direction cross-filter going from Date to Sales.

Warning: Your date table must be contiguous — no gaps. If you generate it with CALENDAR(), this is guaranteed. If you import it from a source system, verify there are no missing dates. A gap in the date table will cause YTD calculations to silently drop rows.


Understanding How DAX Time Intelligence Functions Actually Work

Here's the mental model you need: DAX time intelligence functions are filter modifiers. They don't calculate anything on their own — they generate a table of dates, which is then used as a filter inside CALCULATE.

When you write:

Sales YTD =
CALCULATE(
    [Total Sales],
    DATESYTD('Date'[Date])
)

What's actually happening is:

  1. DATESYTD('Date'[Date]) looks at the current filter context — for example, "March 2024" — and returns a table containing every date from January 1, 2024 through March 31, 2024.
  2. CALCULATE replaces the current date filter with that table of dates.
  3. [Total Sales] evaluates with the expanded filter.

This is why the date table relationship matters so much. DATESYTD generates dates from the Date table, which then filters your fact table through the relationship. If the relationship doesn't exist or isn't marked correctly, that filter has nothing to propagate through.


Building Your Core Measures

Let's work with a realistic scenario: a retail company tracking sales. Your fact table is Sales with columns Order Date, Revenue, and Units Sold. Your base measure is:

Total Revenue =
SUM(Sales[Revenue])

Year-to-Date Revenue

Revenue YTD =
CALCULATE(
    [Total Revenue],
    DATESYTD('Date'[Date])
)

This is clean and production-ready for a standard calendar year. But you'll want to add a blank handler so it doesn't show a result for future dates:

Revenue YTD =
VAR Result =
    CALCULATE(
        [Total Revenue],
        DATESYTD('Date'[Date])
    )
RETURN
IF(ISBLANK([Total Revenue]), BLANK(), Result)

The guard clause IF(ISBLANK([Total Revenue]), BLANK(), Result) prevents the measure from carrying forward the last YTD value into months with no sales. Without it, your YTD line on a chart will continue horizontally into the future — which is visually misleading and frequently catches stakeholders off guard.

Month-to-Date Revenue

Revenue MTD =
CALCULATE(
    [Total Revenue],
    DATESMTD('Date'[Date])
)

And with the blank guard:

Revenue MTD =
VAR Result =
    CALCULATE(
        [Total Revenue],
        DATESMTD('Date'[Date])
    )
RETURN
IF(ISBLANK([Total Revenue]), BLANK(), Result)

Quarter-to-Date Revenue

Revenue QTD =
VAR Result =
    CALCULATE(
        [Total Revenue],
        DATESQTD('Date'[Date])
    )
RETURN
IF(ISBLANK([Total Revenue]), BLANK(), Result)

Tip: DATESMTD, DATESQTD, and DATESYTD all accept an optional second argument for fiscal year end. For a fiscal year ending June 30, write DATESYTD('Date'[Date], "6/30"). The string format is "month/day" using your locale's date separator.

Fiscal Year-to-Date

If your organization runs on a fiscal calendar (say, July 1 through June 30), the built-in DATESYTD with the year-end argument handles this cleanly:

Revenue FYTD =
VAR Result =
    CALCULATE(
        [Total Revenue],
        DATESYTD('Date'[Date], "6/30")
    )
RETURN
IF(ISBLANK([Total Revenue]), BLANK(), Result)

This is one of those things that feels like magic until you understand it: DAX is now resetting its "year" accumulation at July 1 instead of January 1, using nothing more than that date string parameter.


Period-over-Period Comparisons: The Real Power

Cumulative totals are useful, but comparison measures — "how does this period stack up against the same period last year?" — are where time intelligence earns its keep in executive dashboards.

Prior Year Revenue (Same Period)

Revenue PY =
CALCULATE(
    [Total Revenue],
    SAMEPERIODLASTYEAR('Date'[Date])
)

SAMEPERIODLASTYEAR shifts whatever date range is in the current filter context back by exactly one year. If you're looking at March 2024, it returns March 2023. If you're looking at Q2 2024, it returns Q2 2023. It handles the relationship between the date table and your fact table automatically.

Year-over-Year Variance

Revenue YoY Variance =
VAR CurrentRevenue = [Total Revenue]
VAR PriorYearRevenue = [Revenue PY]
RETURN
IF(
    ISBLANK(PriorYearRevenue),
    BLANK(),
    CurrentRevenue - PriorYearRevenue
)

Year-over-Year Variance Percentage

Revenue YoY % =
VAR CurrentRevenue = [Total Revenue]
VAR PriorYearRevenue = [Revenue PY]
RETURN
IF(
    ISBLANK(PriorYearRevenue) || PriorYearRevenue = 0,
    BLANK(),
    DIVIDE(CurrentRevenue - PriorYearRevenue, PriorYearRevenue)
)

Use DIVIDE instead of the / operator here. DIVIDE handles the division-by-zero case gracefully and returns BLANK by default instead of an error — which matters when you have months with no prior year data (new product lines, company acquisitions, etc.).

Tip: Format Revenue YoY % as a percentage in the Measure Tools ribbon. Then in your matrix or table visual, conditional formatting on this column — green for positive, red for negative — gives stakeholders instant visual scanning capability.

Prior Year YTD Comparison

This is a common ask: "How does our YTD this year compare to YTD at the same point last year?"

Revenue YTD PY =
CALCULATE(
    [Revenue YTD],
    SAMEPERIODLASTYEAR('Date'[Date])
)

Yes — you can nest time intelligence functions this way. SAMEPERIODLASTYEAR first shifts the date context back a year, and then DATESYTD (inside [Revenue YTD]) accumulates from the start of that shifted year. The result: your YTD figure as of the same calendar point last year.

Revenue YTD YoY % =
DIVIDE(
    [Revenue YTD] - [Revenue YTD PY],
    [Revenue YTD PY]
)

Using DATEADD for Flexible Period Shifting

SAMEPERIODLASTYEAR is convenient but limited to exactly one year. DATEADD gives you full control over which direction and by how much to shift.

Prior Month Revenue

Revenue PM =
CALCULATE(
    [Total Revenue],
    DATEADD('Date'[Date], -1, MONTH)
)

Prior Quarter Revenue

Revenue PQ =
CALCULATE(
    [Total Revenue],
    DATEADD('Date'[Date], -1, QUARTER)
)

Two Years Ago

Revenue 2YA =
CALCULATE(
    [Total Revenue],
    DATEADD('Date'[Date], -2, YEAR)
)

Month-over-Month Variance

Revenue MoM % =
VAR CurrentRevenue = [Total Revenue]
VAR PriorMonthRevenue = [Revenue PM]
RETURN
IF(
    ISBLANK(PriorMonthRevenue) || PriorMonthRevenue = 0,
    BLANK(),
    DIVIDE(CurrentRevenue - PriorMonthRevenue, PriorMonthRevenue)
)

Warning: DATEADD at the MONTH level can behave unexpectedly at month boundaries. Shifting January 31 back one month produces January 31 shifted to December 31 — which is correct. But shifting March 31 back one month produces February 28 (or 29), which is what you want. DAX handles this correctly, but if you're shifting by days and crossing month boundaries, test your edge cases manually.


Handling Partial Periods: The "To Date" Problem

One of the most common mistakes in time intelligence reporting: comparing a complete prior period to a partial current period.

Imagine it's March 15. Your report shows:

  • February Revenue: $450,000 (full month)
  • March Revenue: $230,000 (only 15 days in)

If a stakeholder sees that table, they might conclude March is dramatically weaker — but you're comparing 28 days to 15 days. This is the partial period problem.

Days Elapsed in Current Period

Days Elapsed Current Month =
VAR LastDateWithData =
    CALCULATE(
        MAX('Date'[Date]),
        Sales
    )
VAR CurrentMonthStart =
    DATE(YEAR(LastDateWithData), MONTH(LastDateWithData), 1)
RETURN
DATEDIFF(CurrentMonthStart, LastDateWithData, DAY) + 1

Prior Year Same Days MTD

This measure calculates last year's revenue for the same number of days into the equivalent month — an apples-to-apples comparison:

Revenue PY MTD Matched =
VAR LastSaleDate = CALCULATE(MAX(Sales[Order Date]))
VAR DayOfMonth = DAY(LastSaleDate)
VAR PYMonthStart =
    DATE(YEAR(LastSaleDate) - 1, MONTH(LastSaleDate), 1)
VAR PYMatchedEnd =
    DATE(YEAR(LastSaleDate) - 1, MONTH(LastSaleDate), DayOfMonth)
RETURN
CALCULATE(
    [Total Revenue],
    'Date'[Date] >= PYMonthStart &&
    'Date'[Date] <= PYMatchedEnd
)

This is the kind of measure that separates a "Power BI developer" from a "data analyst who uses Power BI." It requires understanding the problem, not just knowing the functions.


Building a Running Total Without Time Intelligence Functions

Sometimes you're working with non-standard fiscal calendars, week-based periods, or datasets where the built-in functions don't map cleanly to your periods. In those cases, you can build running totals manually:

Revenue Running Total (Manual) =
CALCULATE(
    [Total Revenue],
    FILTER(
        ALL('Date'),
        'Date'[Year] = MAX('Date'[Year]) &&
        'Date'[Date] <= MAX('Date'[Date])
    )
)

This approach bypasses the time intelligence functions entirely and uses FILTER and ALL to build your own date range. It's more verbose and slightly slower for large datasets, but it's completely transparent and works with any calendar system.

Tip: When working with fiscal calendars stored as custom columns (like Fiscal Year and Fiscal Quarter in your date table), use this manual approach rather than fighting DATESYTD into a fiscal context. Store a Fiscal Day of Year column (1–365) and use it as your accumulation key.


Hands-On Exercise: Building a Sales Performance Dashboard Layer

Let's put everything together. You'll build a complete time intelligence measure library for a retail sales dataset.

Scenario: You're the BI analyst for a regional grocery chain with 12 stores. Your fact table is Sales with columns Order Date, Store ID, Category, and Net Revenue. Your fiscal year runs April 1 through March 31.

Step 1: Create the Date Table

Use the date table DAX from earlier in this lesson, but modify the Fiscal Year and Fiscal Quarter columns for an April 1 start:

"Fiscal Year",      IF(MONTH([Date]) >= 4,
                        "FY" & YEAR([Date]) + 1,
                        "FY" & YEAR([Date])
                    ),
"Fiscal Quarter",   SWITCH(
                        TRUE(),
                        MONTH([Date]) IN {4,5,6},    "FQ1",
                        MONTH([Date]) IN {7,8,9},    "FQ2",
                        MONTH([Date]) IN {10,11,12}, "FQ3",
                        MONTH([Date]) IN {1,2,3},    "FQ4"
                    ),
"Fiscal Month Number", SWITCH(
                        TRUE(),
                        MONTH([Date]) = 4,  1,
                        MONTH([Date]) = 5,  2,
                        MONTH([Date]) = 6,  3,
                        MONTH([Date]) = 7,  4,
                        MONTH([Date]) = 8,  5,
                        MONTH([Date]) = 9,  6,
                        MONTH([Date]) = 10, 7,
                        MONTH([Date]) = 11, 8,
                        MONTH([Date]) = 12, 9,
                        MONTH([Date]) = 1,  10,
                        MONTH([Date]) = 2,  11,
                        MONTH([Date]) = 3,  12
                    )

Step 2: Create a Measures Table

Create an empty table called _Measures using Enter Data (just one column with a placeholder row). Store all your measures here to keep the model organized. This is standard practice in production Power BI models.

Step 3: Build the Base Measure

Total Revenue =
SUMX(
    Sales,
    Sales[Net Revenue]
)

Use SUMX instead of SUM here — it's more flexible when you later need to add row-level logic like filtering out returns or applying promotional pricing adjustments.

Step 4: Build the Full Measure Library

-- Cumulative measures
Revenue MTD =
VAR Result = CALCULATE([Total Revenue], DATESMTD('Date'[Date]))
RETURN IF(ISBLANK([Total Revenue]), BLANK(), Result)

Revenue QTD =
VAR Result = CALCULATE([Total Revenue], DATESQTD('Date'[Date]))
RETURN IF(ISBLANK([Total Revenue]), BLANK(), Result)

Revenue FYTD =
VAR Result = CALCULATE([Total Revenue], DATESYTD('Date'[Date], "3/31"))
RETURN IF(ISBLANK([Total Revenue]), BLANK(), Result)

-- Prior period measures
Revenue PY =
CALCULATE([Total Revenue], SAMEPERIODLASTYEAR('Date'[Date]))

Revenue PM =
CALCULATE([Total Revenue], DATEADD('Date'[Date], -1, MONTH))

Revenue FYTD PY =
CALCULATE([Revenue FYTD], SAMEPERIODLASTYEAR('Date'[Date]))

-- Variance measures
Revenue YoY Variance =
VAR Current = [Total Revenue]
VAR Prior = [Revenue PY]
RETURN IF(ISBLANK(Prior), BLANK(), Current - Prior)

Revenue YoY % =
DIVIDE([Revenue YoY Variance], [Revenue PY])

Revenue MoM % =
DIVIDE(
    [Total Revenue] - [Revenue PM],
    [Revenue PM]
)

Revenue FYTD YoY % =
DIVIDE(
    [Revenue FYTD] - [Revenue FYTD PY],
    [Revenue FYTD PY]
)

Step 5: Verify in a Matrix Visual

Create a matrix visual with:

  • Rows: Date[Year-Month]
  • Values: Total Revenue, Revenue MTD, Revenue FYTD, Revenue PY, Revenue YoY %

Filter to a single store and a single category first. Verify that:

  • MTD resets to the current month's revenue at the start of each month
  • FYTD resets at April (not January)
  • YoY % shows blank for periods with no prior year data

Then remove the store/category filter and verify the measures still aggregate correctly across all stores.


Common Mistakes & Troubleshooting

YTD Returns Blank Everywhere

Cause: The date table is not marked as a date table, or the relationship between the date table and fact table doesn't exist or is inactive.

Fix: In the Data pane, select your date table, go to Table Tools, and confirm "Mark as date table" is applied. Then check the model view to confirm the relationship exists and is active (solid line, not dotted).

YTD Shows the Same Value for Every Month

Cause: The Date column in your date table has a data type of Text instead of Date. DAX time intelligence functions require a true Date type.

Fix: In Power Query, select the date column, and change the data type to Date. If the column was imported as text, you may need to parse it with Date.From([DateColumn]).

Prior Year Measure Returns Blank for Current Year

Cause: Your date table doesn't extend far enough back. If your data starts in 2022, your date table must start in at least 2021 to have prior year values for 2022.

Fix: Extend your date table's StartDate variable back one additional year beyond your earliest data point.

YTD Shows Future Months as the Same Value

Cause: Missing the blank guard clause. The cumulative nature of YTD means the last available value carries forward.

Fix: Wrap the result in IF(ISBLANK([Total Revenue]), BLANK(), Result) as shown in the measures throughout this lesson.

MoM% Shows Wild Swings in January

Cause: This is often correct but unexpected. If your business is seasonal and January is genuinely different from December, DATEADD(-1, MONTH) is doing the right thing. But if it's wrong, check whether your date table has any gaps in December or January.

Fix: Run COUNTROWS('Date') as a measure and verify the count equals the number of days in your expected range. For a 2020–2025 date table, you expect 2192 rows (accounting for leap years).

SAMEPERIODLASTYEAR Returns Wrong Values for Leap Year February

Cause: If February 29, 2024 is in scope, SAMEPERIODLASTYEAR tries to find February 29, 2023 — which doesn't exist. DAX handles this by returning February 28, 2023, which is the correct behavior. If your numbers look off, it's likely a data issue in the source, not a DAX issue.

Fix: Verify the raw data for late February in both years and check whether the sales date logic in your source system handles this correctly.

Time Intelligence Functions Don't Work in DirectQuery Mode

Cause: Several DAX time intelligence functions are not supported in DirectQuery mode because they require DAX to iterate over date sets.

Fix: Either switch to Import mode for your date table (a hybrid model is valid — Import for the date table, DirectQuery for the fact table), or rewrite your measures using the manual FILTER + ALL approach shown earlier in this lesson. The manual approach translates into SQL that DirectQuery can push down to the source.


Performance Considerations

For most datasets under a few million rows, the measures in this lesson will perform fine. But here are the patterns that cause trouble at scale:

Avoid deeply nested time intelligence functions. Nesting DATEADD inside CALCULATE inside another CALCULATE creates multiple filter context transitions. For complex scenarios, compute the date range explicitly with VAR before calling CALCULATE:

Revenue Rolling 90 Days =
VAR EndDate = MAX('Date'[Date])
VAR StartDate = EndDate - 89
RETURN
CALCULATE(
    [Total Revenue],
    DATESBETWEEN('Date'[Date], StartDate, EndDate)
)

DATESBETWEEN is often faster than DATEADD for fixed ranges. When you know the start and end dates explicitly, DATESBETWEEN generates a single efficient filter rather than iterating over the date column.

Avoid using time intelligence in row-level calculated columns. Time intelligence functions are context-aware and designed for measure contexts. Using them in calculated columns can produce unexpected results and performance problems. Put time logic in measures, and use simple date arithmetic in calculated columns.


Summary & Next Steps

You've now built a complete, production-ready time intelligence layer from the ground up. Let's recap what you've established:

  • A properly configured date table with both calendar and fiscal year support
  • A full suite of cumulative measures (MTD, QTD, FYTD) with proper blank handling
  • Prior period comparisons using SAMEPERIODLASTYEAR and DATEADD
  • Variance measures in both absolute and percentage terms
  • A manual approach for non-standard calendars or DirectQuery scenarios
  • Techniques for handling partial periods without misleading your stakeholders

The measures you've built in this lesson are the backbone of almost every serious Power BI report. A sales leadership dashboard, a supply chain analysis, a financial P&L tracker — they all need the same core layer you've just assembled.

Where to go next:

  • Advanced calendar patterns: Explore 4-4-5 retail calendars and ISO week-based fiscal years, which require a fundamentally different approach to the date table
  • Rolling averages and moving windows: Learn to build 7-day rolling averages, 13-week trends, and other window calculations using DATESINPERIOD
  • Dynamic period selection: Use disconnected parameter tables to let users switch between "vs. prior year," "vs. prior quarter," and "vs. budget" from a single slicer
  • DAX performance optimization: Dive into DAX Studio to measure query plan efficiency for your time intelligence measures on large datasets

The next level of time intelligence mastery is less about learning new functions and more about understanding the filter context mechanics that make all these functions work — and that's where advanced DAX really begins.

Learning Path: Getting Started with Power BI

Previous

Introduction to DAX: Writing Your First Calculated Columns and Measures in Power BI

Related Articles

Power BI🌱 Foundation

Designing a Star Schema Data Model in Power BI Desktop for Enterprise Reporting

16 min
Power BI🌱 Foundation

DAX Text and String Functions: Cleaning, Parsing, and Categorizing Data with SEARCH, SUBSTITUTE, and FORMAT

14 min
Power BI🌱 Foundation

Introduction to DAX: Writing Your First Calculated Columns and Measures in Power BI

15 min

On this page

  • Introduction
  • Prerequisites
  • Why Time Intelligence Requires a Dedicated Date Table
  • Building Your Date Table
  • Understanding How DAX Time Intelligence Functions Actually Work
  • Building Your Core Measures
  • Year-to-Date Revenue
  • Month-to-Date Revenue
  • Quarter-to-Date Revenue
  • Fiscal Year-to-Date
  • Period-over-Period Comparisons: The Real Power
  • Year-over-Year Variance Percentage
  • Prior Year YTD Comparison
  • Using DATEADD for Flexible Period Shifting
  • Prior Month Revenue
  • Prior Quarter Revenue
  • Two Years Ago
  • Month-over-Month Variance
  • Handling Partial Periods: The "To Date" Problem
  • Days Elapsed in Current Period
  • Prior Year Same Days MTD
  • Building a Running Total Without Time Intelligence Functions
  • Hands-On Exercise: Building a Sales Performance Dashboard Layer
  • Step 1: Create the Date Table
  • Step 2: Create a Measures Table
  • Step 3: Build the Base Measure
  • Step 4: Build the Full Measure Library
  • Step 5: Verify in a Matrix Visual
  • Common Mistakes & Troubleshooting
  • YTD Returns Blank Everywhere
  • YTD Shows the Same Value for Every Month
  • Prior Year Measure Returns Blank for Current Year
  • YTD Shows Future Months as the Same Value
  • MoM% Shows Wild Swings in January
  • SAMEPERIODLASTYEAR Returns Wrong Values for Leap Year February
  • Time Intelligence Functions Don't Work in DirectQuery Mode
  • Performance Considerations
  • Summary & Next Steps
  • Prior Year Revenue (Same Period)
  • Year-over-Year Variance
  • Year-over-Year Variance Percentage
  • Prior Year YTD Comparison
  • Using DATEADD for Flexible Period Shifting
  • Prior Month Revenue
  • Prior Quarter Revenue
  • Two Years Ago
  • Month-over-Month Variance
  • Handling Partial Periods: The "To Date" Problem
  • Days Elapsed in Current Period
  • Prior Year Same Days MTD
  • Building a Running Total Without Time Intelligence Functions
  • Hands-On Exercise: Building a Sales Performance Dashboard Layer
  • Step 1: Create the Date Table
  • Step 2: Create a Measures Table
  • Step 3: Build the Base Measure
  • Step 4: Build the Full Measure Library
  • Step 5: Verify in a Matrix Visual
  • Common Mistakes & Troubleshooting
  • YTD Returns Blank Everywhere
  • YTD Shows the Same Value for Every Month
  • Prior Year Measure Returns Blank for Current Year
  • YTD Shows Future Months as the Same Value
  • MoM% Shows Wild Swings in January
  • SAMEPERIODLASTYEAR Returns Wrong Values for Leap Year February
  • Time Intelligence Functions Don't Work in DirectQuery Mode
  • Performance Considerations
  • Summary & Next Steps