Wednesday, January 21, 2026

Does Calendar-Primarily based Time-Intelligence Change Customized Logic?


Introduction

calendar-based Time Intelligence, the necessity for customized Time Intelligence logic has decreased dramatically.

Now, we are able to create customized calendars to satisfy our Time Intelligence calculation wants.

You may need learn my article about superior Time Intelligence:

https://towardsdatascience.com/advanced-time-intelligence-in-dax-with-performance-in-mind/

A lot of the customized logic is now not wanted.

However we nonetheless have eventualities the place we should have customized calculations, like working common.

A while in the past, SQLBI wrote an article about calculating the working common.

This piece makes use of the identical ideas described there in a barely completely different strategy.

Let’s see how we are able to calculate the working common over three months by utilizing the brand new Calendars.

Utilizing basic Time Intelligence

First, we use the usual Gregorian calendar with the basic Time Intelligence date desk.

I take advantage of the same strategy as described within the SQLBI article linked within the References part beneath.

Working Common by Month = 
// 1. Get the primary and final Date for the present Filter Context
VAR MaxDate = MAX( 'Date'[Date] )


// 2. Generate the Date vary wanted for the Transferring common (three months)
VAR  DateRange =
 DATESINPERIOD( 'Date'[Date]
        ,MaxDate
        ,-3
        ,MONTH
    )

// 3. Generate a desk filtered by the Date Vary generated at step 2
// This desk accommodates solely three rows
VAR SalesByMonth = 
    CALCULATETABLE(
        SUMMARIZECOLUMNS(
            'Date'[MonthKey]
            , "#Gross sales", [Sum Online Sales]
            
        )
        ,DateRange
    )

RETURN
    // 4. Calculate the Common over the three values within the desk generate in step 3
    AVERAGEX(SalesByMonth, [#Sales])

When executing this measure in DAX Studio, I get the anticipated outcomes:

Determine 1 – Working Common over three months with the basic Time Intelligence strategy (Determine by the Writer)

To this point, so good.

Utilizing an ordinary calendar

Subsequent, I created a Calendar named “Gregorian Calendar” and altered the code to make use of this calendar.

To make this simpler to grasp, I copied the date desk to a brand new desk named “Gregorian Date Desk”.

The change is when calling the DATESINPERIOD() perform.

As an alternative of utilizing the date column, I take advantage of the newly created calendar:

Working Common by Month = 
// 1. Get the primary and final Date for the present Filter Context
VAR MaxDate = MAX( 'Gregorian Date Desk'[Date] )


// 2. Generate the Date vary wanted for the Transferring common (three months)
VAR  DateRange =
 DATESINPERIOD( 'Gregorian Calendar'
        ,MaxDate
        ,-3
        ,MONTH
    )



// 3. Generate a desk filtered by the Date Vary generated at step 2
// This desk accommodates solely three rows
VAR SalesByMonth = 
    CALCULATETABLE(
        SUMMARIZECOLUMNS(
            'Gregorian Date Desk'[MonthKey]
            , "#Gross sales", [Sum Online Sales]
            
        )
        ,DateRange
    )

RETURN
    // 4. Calculate the Common over the three values within the desk generate in step 3
    AVERAGEX(SalesByMonth, [#Sales])

As anticipated, the outcomes are an identical:

Determine 2 – Identical End result as earlier than when utilizing the Calendar (Determine by the Writer)

The efficiency is superb, as this question completes in 150 milliseconds.

Utilizing a customized calendar

However what occurs when utilizing a customized calendar?

For instance, a calendar with 15 months per 12 months and 31 days for every month?

I created such a calendar for my article, which describes use circumstances for calendar-based Time Intelligence (See the Hyperlink on the High and within the References part).

If you take a look at the code for the measure, you’ll discover that it’s completely different:

Working Common by Month (Customized) = 
    VAR LastSelDate = MAX('Monetary Calendar'[CalendarEndOfMonthDate])

    VAR MaxDateID = CALCULATE(MAX('Monetary Calendar'[ID_Date])
                                ,REMOVEFILTERS('Monetary Calendar')
                                ,'Monetary Calendar'[CalendarEndOfMonthDate] = LastSelDate
                                )

    VAR MinDateID = CALCULATE(MIN('Monetary Calendar'[ID_Date])
                                ,REMOVEFILTERS('Monetary Calendar')
                                ,'Monetary Calendar'[CalendarEndOfMonthDate] = EOMONTH(LastSelDate, -2)
                                )

    VAR SalesByMonth = 
        CALCULATETABLE(
            SUMMARIZECOLUMNS(
                'Monetary Calendar'[CalendarYearMonth]
                , "#Gross sales", [Sum Online Sales]
                
            )
            ,'Monetary Calendar'[ID_Date] >= MinDateID
                && 'Monetary Calendar'[ID_Date] <= MaxDateID
        )

    RETURN
    AVERAGEX(SalesByMonth, [#Sales])

The rationale for the adjustments is that this desk lacks a date column usable with the DATESINPERIOD() perform. Because of this, I need to use customized code to calculate the worth vary for ID_Date.

These are the outcomes:

Determine 3 – Outcomes of the working common when utilizing a customized calendar with no Dates (Determine by the Writer)

As you’ll be able to test, the outcomes are appropriate.

Optimizing by utilizing a day index

However once I analyze the efficiency, it’s not that nice.

It takes nearly half a second to calculate the outcomes.

We are able to enhance efficiency by eradicating the necessity to retrieve the minimal and most ID_Date and performing a extra environment friendly calculation.

I do know that every month has 31 days.

To return three months, I do know that I need to return by 93 days.

I can use this to create a quicker model of the measure:

Working Common by Month (Monetary) = 
    // Step 1: Get the final Month (ID)
    VAR SelMonth = MAX('Monetary Calendar'[ID_Month])
    
    // Step 2: Generate the Date Vary from the final 93 days
    VAR DateRange =
        TOPN(93
        ,CALCULATETABLE(
                    SUMMARIZECOLUMNS('Monetary Calendar'[ID_Date])
                    ,REMOVEFILTERS('Monetary Calendar')
                    ,'Monetary Calendar'[ID_Month] <= SelMonth
                )
                ,'Monetary Calendar'[ID_Date], DESC
            )
    
    
    // 3. Generate a desk filtered by the Date Vary generated at step 2
    // This desk accommodates solely three rows
    VAR SalesByMonth = 
        CALCULATETABLE(
            SUMMARIZECOLUMNS(
                'Monetary Calendar'[ID_Month]
                , "#Gross sales", [Sum Online Sales]
                
            )
            ,DateRange
        )
    
    RETURN
        // 4. Calculate the Common over the three values within the desk generate in step 3
        AVERAGEX(SalesByMonth, [#Sales])

This time, I used the TOPN() perform to retrieve the 93 earlier rows from the Monetary Calendar desk and used this record as a filter.

The outcomes are an identical to the earlier model:

Determine 4 – Outcomes of the Model which makes use of the final 93 days (Determine by the Writer)

This model wants solely 118 ms to finish.

However can we go even additional with the optimization?

Subsequent, I added a brand new column to the Fiscal Calendar to assign ranks to the rows. Now, every date has a singular quantity which is in direct correlation to the order of them:

Determine 5 – Extract from the Monetary Calendar desk with the RowRank column (Determine by the Writer)

The measure utilizing this column is the next:

Working Common by Month (Monetary) = 
    // Step 1: Get the final Month (ID)
    VAR MaxDateRank = MAX('Monetary Calendar'[ID_Date_RowRank])
    
    // Step 2: Generate the Date Vary from the final 93 days
    VAR DateRange =
            CALCULATETABLE(
                        SUMMARIZECOLUMNS('Monetary Calendar'[ID_Date])
                        ,REMOVEFILTERS('Monetary Calendar')
                        ,'Monetary Calendar'[ID_Date_RowRank] <= MaxDateRank
                            && 'Monetary Calendar'[ID_Date_RowRank] >= MaxDateRank - 92
                    )
                    --ORDER BY 'Monetary Calendar'[ID_Date] DESC
    
    
    // 3. Generate a desk filtered by the Date Vary generated at step 2
    // This desk accommodates solely three rows
    VAR SalesByMonth = 
        CALCULATETABLE(
            SUMMARIZECOLUMNS(
                'Monetary Calendar'[ID_Month]
                , "#Gross sales", [Sum Online Sales]
                
            )
            ,DateRange
        )
    
    RETURN
        // 4. Calculate the Common over the three values within the desk generate in step 3
        AVERAGEX(SalesByMonth, [#Sales])

The consequence is similar, I don’t present it once more.

However right here is the comparability from the execution statistics:

Determine 6 – Execution statistics of the 2 Measures. On prime, you see the statistics for the one utilizing TOPN(). Beneath are the statistics for the one utilizing the RowRank column (Determine by the Writer)

As you’ll be able to see, the Model utilizing TOPN() is barely slower than the one utilizing the RowRank column.

However the variations are marginal.

Extra importantly, the model utilizing the RowRank column requires extra knowledge to finish the calculations. See the Rows column for particulars.

This implies extra RAM utilization.

However with this small variety of rows, the variations are nonetheless marginal.

It’s your selection which model you favor.

Utilizing a weekly calendar

Lastly, let’s take a look at a week-based calculation.

This time, I need to calculate the rolling common during the last three weeks.

Because the calendar-based Time Intelligence permits for the creation of a week-based calendar, the measure is similar to the second:

Working Common by Week = 
// 1. Get the primary and final Date for the present Filter Context
VAR MaxDate = MAX( 'Gregorian Date Desk'[Date] )


// 2. Generate the Date vary wanted for the Transferring common (three months)
VAR  DateRange =
 DATESINPERIOD( 'Week Calendar'
        ,MaxDate
        ,-3
        ,WEEK
    )



// 3. Generate a desk filtered by the Date Vary generated at step 2
// This desk accommodates solely three rows
VAR SalesByMonth = 
    CALCULATETABLE(
        SUMMARIZECOLUMNS(
            'Gregorian Date Desk'[WeekKey]
            , "#Gross sales", [Sum Online Sales]
            
        )
        ,DateRange
    )

RETURN
    // 4. Calculate the Common over the three values within the desk generate in step 3
    AVERAGEX(SalesByMonth, [#Sales])

The important thing half is that I take advantage of the “WEEK” parameter within the DATESINPERIOD() name.
That’s all.

That is the results of the question:

Determine 7 – End result for the working common over three weeks (Determine by the Writer)

The efficiency is superb, with execution occasions beneath 100 ms.

Remember that weekly calculations are solely attainable with the calendar-based Time Intelligence.

Conclusion

As you might have seen, the calendar-based Time Intelligence makes life simpler with customized logic: we solely must cross the calendar as a substitute of a date column to the features. And we are able to calculate weekly intervals.

However the present characteristic set doesn’t embody a semester interval. Once we should calculate semester-based outcomes, we should both use basic Time Intelligence or write customized code.

However we nonetheless want customized logic, particularly once we don’t have a date column in our calendar desk. In such circumstances, we are able to’t use the usual time intelligence features, as they nonetheless work with date columns.

Bear in mind: An important process when working with calendar-based Time Intelligence is constructing a constant and full calendar desk. From my expertise, that is probably the most complicated process.

As a sidenote, I discovered some fascinating features on daxlib.org a few working common.

I added a hyperlink to the features within the References part beneath.

These features observe a very completely different sample, however I wished to incorporate them to create a whole image of this matter.

References

The talked about SQLBI.com article on calculating the working Common:

https://www.sqlbi.com/articles/rolling-12-months-average-in-dax

Time Sequence features on daxlib.org with a unique strategy:

https://daxlib.org/package deal/TimeSeries.MovingAverage

Right here is my final article, the place I clarify Calendar-based Time-Intelligence:

https://towardsdatascience.com/use-cases-for-the-new-calendar-based-time-intelligence/

Like in my earlier articles, I take advantage of the Contoso pattern dataset. You may obtain the ContosoRetailDW Dataset at no cost from Microsoft right here.

The Contoso Information can be utilized freely beneath the MIT License, as described on this doc. I modified the dataset to shift the information to up to date dates.

Related Articles

Latest Articles