Wicked Smart Data
LearnInsightsAboutContact
Sign InLet's Build
LearnInsightsAboutContact
Sign InLet's Build
Wicked Smart Data

Intelligence, automation, and expert execution — plus an elite library of free knowledge. We turn complexity into competitive advantage.

Start a conversation

Platform

  • Learning Paths
  • Insights
  • RSS Feed

Company

  • About
  • Contact
  • Work With Us

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Wicked Smart Data. All rights reserved.

Intelligence · Automation · Advantage

All Insights
Power BI

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

Time intelligence is what transforms a static Power BI report into a living analysis — but most practitioners get it subtly wrong. This lesson walks you through building a complete, production-ready suite of YTD, MTD, and period-over-period measures from scratch, including fiscal calendar support and partial period handling.

⚡ Practitioner19 min readJul 10, 2026Updated Aug 17, 2026
Mastering Time Intelligence in Power BI: Building YTD, MTD, and Period-over-Period DAX Measures
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
  • 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
  • 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.

    Work With Us

    From insight to implementation

    Reading is the start. When you're ready to build the data, automation, or AI systems behind it, our team turns strategy into shipped results.

    Let's Build

    Getting Started with Power BI

    Previous

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

    Next

    Mastering DAX Variables, CALCULATE Context Transition, and Iterator Functions for Complex Business Logic in Power BI

    Related Insights

    Power BIFoundation

    Power BI Personal Gateway vs. On-Premises Data Gateway: Choosing the Right Refresh Architecture

    17 min
    Power BIFoundation

    DAX Relationships 101: How Power BI Filters Flow Across Tables and Why It Matters for Your Measures

    15 min
    Power BIFoundation

    Understanding Power BI Relationships: How to Connect Tables, Set Cardinality, and Avoid Common Modeling Mistakes

    17 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
    • 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