The September 2025 update for Custom Calendars in Power BI looked, at first, like time intelligence was finally going to stop demanding a blood sacrifice. Built-in weekly and custom logic inside Tabular models is a genuine efficiency win. But anyone who has debugged a production model during a leap year knows that “Preview” features come with teeth, and DAX rarely fails outright. It drifts quietly instead.
The gotchas I keep running into with these calendar features are not syntax errors. They are architectural quirks, and they can leave your Year-Over-Year (YOY) reports reading like they were calculated by a broken clock. If you are aiming for a robust like-for-like Power BI model, these are worth knowing before the model ships.
The leap year shift in custom calendars
The first oddity shows up in leap years. Use DATEADD against a Custom Calendar and DAX falls back on a mechanism called “Distance from Parent.” If your Parent is defined as the Year, DAX measures how far a date sits from the start of that year, then tries to reproduce the same distance in the year before.
Compare 2024, a leap year, against 2025 and the PY values slide by exactly one day from March onward. It is a subtle bug, and it wrecks the row-level integrity of your visuals. The naive version that causes it:
Online Sales (PY Gregorian) =
CALCULATE(
[Online Sales],
DATEADD('Gregorian Calendar', -1, YEAR)
)
It reads fine, but the year-length difference maps March 2025 values onto the wrong day in 2024. By December, DAX starts folding the last two days of the year into a single row as it tries to reconcile the unequal lengths. The drift traces back to the “parent” (Year) changing size.
Fixing it with month granularity
The fix is not a giant custom table, though that route works. Refactor the DATEADD logic so it steps back by months instead of years. Shifting the granularity to 12 months sidesteps the “Distance from Parent” quirk that breaks over a leap year boundary. The corrected measure:
Online Sales (-12 M Gregorian) =
CALCULATE(
[Online Sales],
DATEADD('Gregorian Calendar', -12, MONTH)
)
In my tests that killed the 1-day drift and left the quarter and year totals accurate. It also beats the old war story fix of building a custom calendar where every month has 31 days, purely to force consistency.
Weekly logic and the “consistent categorization” error
Mixing weekly logic with monthly reporting is the next place things jam up. Clients want daily results for the current month set against the same week and weekday of the previous year. Weeks do not line up neatly with months, though, so you cannot just bolt a Month category onto a weekly calendar table.
Microsoft’s engine wants consistent categorization across every calendar on the same table. Call DATESMTD() on a calendar with no month category and you get a validation error. My guide on optimizing DAX filtering covers keeping model performance sane once these filters get complicated.
If Custom Calendars are eating your dev hours, hand it to me. I have been wrestling with WordPress and enterprise data integrations since the 4.x days, and I know where the bodies are buried in these preview features.
Where this leaves tabular time intelligence
The new Custom Calendars in Power BI and Fabric are a real improvement, but they are not “set it and forget it.” When the periods are of equal length, like weeks, the logic holds up. When they are not, like Gregorian months across a leap year, you have to think like the architect rather than the user. Refactor your DATEADD parameters, watch the parent-child distances, and validate your totals against a raw date-for-date check before the client sees the report.