See your company like never before
Power BI deep-dives, migration playbooks, and data strategy for enterprise teams.


Join dozens of organizations who have moved to Beyond The Analytics. Book your personalized demo today
Master DAX time intelligence in Power BI — YTD, YOY, rolling averages, DATEADD, and Hijri calendar patterns for UAE & Saudi reporting.
Quick answer: DAX time intelligence functions are a set of 35+ built-in DAX functions that manipulate date-based filter contexts in Power BI, enabling calculations like year-to-date totals, year-over-year comparisons, rolling averages, and period-over-period analysis without writing complex filter logic manually.
DAX time intelligence functions form the backbone of any serious Power BI reporting model. Whether you are building executive dashboards for a Dubai government entity tracking We the UAE 2031 KPIs or a Saudi retail chain comparing Ramadan sales across years, these functions handle the date math that would otherwise require dozens of lines of manual filter logic.
The core requirement: a dedicated date table with contiguous dates, marked as a date table in the model, with an active relationship to every fact table. Without this foundation, time intelligence functions return incorrect results or fail silently.
As of early 2026, Power BI supports two approaches. The classic approach uses functions like TOTALYTD, SAMEPERIODLASTYEAR, and DATEADD. The calendar-based approach, previewed in September 2025, adds support for fiscal years, 4-4-5 retail calendars, and ISO week structures. This guide covers both, with GCC-specific patterns for Hijri calendar reporting.
For teams still transitioning from spreadsheet-based reporting, our Excel to Power BI migration guide covers the move from manual date formulas to the DAX time intelligence framework.
Quick answer: Create a dedicated date table using the DAX CALENDAR or CALENDARAUTO function, add calculated columns for year, quarter, month, and week attributes, mark it as a date table, and relate it to every fact table in the model.
Microsoft's official guidance specifies three hard requirements: the date column must contain unique values, must have no blanks, and must span full calendar years with no gaps.
The most reliable approach is generating the table in DAX using CALENDAR:
DateTable =
VAR MinDate = DATE(2020, 1, 1)
VAR MaxDate = DATE(2026, 12, 31)
RETURN
ADDCOLUMNS(
CALENDAR(MinDate, MaxDate),
"Year", YEAR([Date]),
"Quarter", "Q" & QUARTER([Date]),
"MonthNumber", MONTH([Date]),
"Month", FORMAT([Date], "MMMM"),
"YearMonth", FORMAT([Date], "YYYY-MM"),
"WeekNumber", WEEKNUM([Date], 2),
"DayOfWeekNumber", WEEKDAY([Date], 2),
"IsWeekend", WEEKDAY([Date], 2) >= 6
)
After creating this table, mark it as a date table: Table tools > Mark as date table, selecting the Date column.
GCC countries observe a Monday-to-Friday work week (the UAE shifted from Sunday-Thursday in January 2022). Add an IsWorkingDay column that accounts for regional public holidays — which shift annually for Hijri-based holidays like Eid al-Fitr and Eid al-Adha. Maintain a separate holiday reference table and merge it during Power Query processing.
Quick answer: Year-to-date, quarter-to-date, and month-to-date calculations use either the shorthand functions (TOTALYTD, TOTALQTD, TOTALMTD) or the more flexible CALCULATE + DATESYTD / DATESQTD / DATESMTD pattern — both produce identical results, but the CALCULATE approach handles complex filters more reliably.
The simplest way to write a YTD measure:
Revenue YTD = TOTALYTD(SUM(Sales[Revenue]), DateTable[Date])
TOTALYTD accepts an optional third parameter for fiscal year end dates — critical for organizations whose fiscal year does not end on December 31. The same pattern applies to TOTALQTD and TOTALMTD for quarter-to-date and month-to-date respectively. Since September 2025, Power BI also supports TOTALWTD for week-to-date calculations, though this requires the new calendar-based time intelligence configuration (currently in preview).
As SQLBI explains in detail, TOTALYTD is syntactic sugar for CALCULATE with DATESYTD. The equivalent measure:
Revenue YTD =
CALCULATE(
SUM(Sales[Revenue]),
DATESYTD(DateTable[Date])
)
The CALCULATE approach is preferred: it allows multiple filter arguments, avoids TOTALYTD's error-prone string parameter, and follows a consistent pattern across all measures.
Both the UAE and Saudi Arabia default to a January-to-December fiscal year. Saudi Arabia adopted Gregorian fiscal reporting in 2016. Some GCC entities use non-standard fiscal years. For an April-to-March fiscal year:
Revenue Fiscal YTD =
CALCULATE(
SUM(Sales[Revenue]),
DATESYTD(DateTable[Date], "3/31")
)
The second parameter "3/31" tells DAX that the fiscal year ends on March 31. The year portion of this string is ignored.
Quick answer: Use SAMEPERIODLASTYEAR or DATEADD with a -1 year offset to shift the current filter context back by one year, then calculate the difference or percentage change against the current period value.
Year-over-year analysis is the most requested time intelligence pattern in GCC enterprise dashboards — comparing this quarter's government KPI scores to the same quarter last year, or this month's pipeline value against the prior year baseline.
Revenue LY =
CALCULATE(
SUM(Sales[Revenue]),
SAMEPERIODLASTYEAR(DateTable[Date])
)
SAMEPERIODLASTYEAR is internally equivalent to DATEADD(DateTable[Date], -1, YEAR). It shifts the entire current date filter context back by exactly one year.
Revenue YOY % =
VAR CurrentRevenue = SUM(Sales[Revenue])
VAR PriorYearRevenue = [Revenue LY]
RETURN
DIVIDE(
CurrentRevenue - PriorYearRevenue,
PriorYearRevenue
)
Use DIVIDE instead of the / operator to handle division-by-zero gracefully — it returns BLANK() when the denominator is zero.
Combining YTD with YOY is a common executive reporting pattern:
Revenue YTD LY =
CALCULATE(
SUM(Sales[Revenue]),
DATESYTD(
SAMEPERIODLASTYEAR(DateTable[Date])
)
)
This returns the year-to-date revenue as of the same point in the prior year — enabling an apples-to-apples comparison of how the current year is tracking against last year at the same stage.
Quick answer: SAMEPERIODLASTYEAR shifts dates back exactly one year. DATEADD shifts dates by any number of days, months, quarters, or years while preserving the original date granularity. PARALLELPERIOD shifts dates but always returns complete periods at the specified granularity, expanding partial selections to full months, quarters, or years.
These three functions overlap but behave differently at the edges. Choosing the wrong one leads to subtle calculation errors. The SQLBI comparison is the definitive reference.
DATEADD(DateTable[Date], <number_of_intervals>, <interval>)
DATEADD supports four intervals: DAY, MONTH, QUARTER, YEAR. It shifts the current date filter context by the specified number of intervals while preserving the granularity of the original selection. If the filter context is March 10-20 and you shift by -1 month, you get February 10-20. This makes DATEADD the most versatile period comparison function.
PARALLELPERIOD(DateTable[Date], <number_of_intervals>, <interval>)
PARALLELPERIOD always returns complete periods. If the context is March 10-20 and you shift by -1 month, it returns all of February (1-28/29), not just February 10-20. It supports only MONTH, QUARTER, and YEAR — no DAY interval.
| Scenario | Function | Reason |
|---|---|---|
| Same month last year | DATEADD -1 YEAR | Preserves exact date range |
| Full prior quarter | PARALLELPERIOD -1 QUARTER | Returns complete quarter |
| Last year (shorthand) | SAMEPERIODLASTYEAR | Cleaner syntax for -1 YEAR |
| Trailing 90 days | DATEADD -90 DAY | Only DATEADD supports DAY |
For GCC government dashboards, DATEADD with quarterly offsets is the standard pattern for tracking performance against the same quarter in the prior year.
Quick answer: Use CALCULATE with DATESINPERIOD to define a rolling window of N days, months, or quarters, then apply SUM or AVERAGEX over that window to create rolling totals and moving averages.
Rolling averages smooth out seasonal spikes — essential in GCC markets where Ramadan, summer, and year-end budget cycles create sharp periodic swings.
Revenue Rolling 3M Avg =
CALCULATE(
AVERAGEX(
VALUES(DateTable[YearMonth]),
CALCULATE(SUM(Sales[Revenue]))
),
DATESINPERIOD(
DateTable[Date],
MAX(DateTable[Date]),
-3,
MONTH
)
)
DATESINPERIOD creates a contiguous date window from a reference point. Change -3, MONTH to -12, MONTH for a rolling annual total, or -90, DAY for a trailing 90-day window. A detailed SQLBI walkthrough covers advanced rolling average patterns including calculation groups.
Power BI also supports MOVINGAVERAGE as a visual calculation (MOVINGAVERAGE([SalesAmount], 6)), but visual calculations cannot be reused across visuals. For production dashboards, the CALCULATE + DATESINPERIOD pattern remains the standard.
Quick answer: Build a dual-calendar date table that maps every Gregorian date to its Hijri equivalent using Power Query's culture-aware date formatting or a pre-computed lookup table, then use standard DAX time intelligence functions against the Gregorian dates while displaying Hijri dates in report visuals.
Hijri calendar support is a practical requirement for GCC organizations. Saudi government entities reference the Umm al-Qura calendar for religious observances and administrative processes, and the UAE uses Hijri dates in official documents. While both countries use Gregorian fiscal reporting, many operational reports and HR systems still require Hijri dates.
DAX time intelligence functions assume 12 fixed-length months in a 365/366-day Gregorian year. The Hijri calendar has 12 lunar months of 29 or 30 days in a 354 or 355-day year — approximately 10.87 days shorter than a Gregorian year. Hijri months drift across Gregorian seasons over a 33-year cycle. No DAX function handles this natively.
The proven approach is a date table with both Gregorian and Hijri columns:
// In Power Query (M language), add Hijri columns:
// HijriDateText = Date.ToText([Date], "yyyy/MM/dd", "ar-SA")
// Then split into HijriYear, HijriMonth, HijriDay
The "ar-SA" culture code converts Gregorian dates to Hijri text using the Umm al-Qura calendar. After splitting into year, month, and day columns, the date table contains both calendars mapped to each row.
For Hijri year-to-date calculations, use CALCULATE with explicit filters rather than DATESYTD:
Revenue Hijri YTD =
VAR CurrentHijriYear =
MAX(DateTable[HijriYear])
RETURN
CALCULATE(
SUM(Sales[Revenue]),
DateTable[HijriYear] = CurrentHijriYear,
DateTable[Date] <= MAX(DateTable[Date])
)
The same pattern extends to Hijri quarter-to-date and month-to-date by filtering on HijriMonth or a HijriQuarter column.
Year-over-year on the Hijri calendar requires offsetting by Hijri year, not Gregorian year:
Revenue Hijri LY =
VAR CurrentHijriYear =
MAX(DateTable[HijriYear])
VAR CurrentHijriMonth =
MAX(DateTable[HijriMonthNumber])
RETURN
CALCULATE(
SUM(Sales[Revenue]),
DateTable[HijriYear] = CurrentHijriYear - 1,
DateTable[HijriMonthNumber] = CurrentHijriMonth
)
Because a Hijri year is shorter than a Gregorian year, SAMEPERIODLASTYEAR will not align Hijri months correctly. Explicit Hijri column filters are the only reliable approach.
Quick answer: The September 2025 Power BI release introduced calendar-based time intelligence (currently in preview), allowing custom calendar definitions — fiscal, retail 4-4-5, ISO week, and others — directly in the data model, with new week-level functions like TOTALWTD and DATESWTD that were not previously available.
Classic DAX time intelligence assumes a Gregorian calendar. For 15 years, non-standard calendars required manual workarounds. The calendar-based time intelligence preview changes this.
TOTALWTD, DATESWTD, STARTOFWEEK, ENDOFWEEK, PREVIOUSWEEK, NEXTWEEK — previously unavailable because DAX had no way to define a "week"As of March 2026, this feature remains in preview and does not handle Hijri lunar calendars natively. For production models, continue using classic time intelligence for Gregorian calculations and the dual-calendar pattern for Hijri requirements.
Quick answer: The most common mistakes are missing or incomplete date tables, not marking the table as a date table, using TOTALYTD when CALCULATE + DATESYTD would be safer, confusing DATEADD with PARALLELPERIOD behavior, and applying time intelligence functions to columns that are not in the date table.
DATEADD and DATESYTD. The table must contain every consecutive calendar date. Filter non-working days in measures, not in the table."3/31"), not a date function. Passing DATE(2026, 3, 31) is a common error — the CALCULATE + DATESYTD pattern avoids this.PARALLELPERIOD -1 MONTH returns all of February, not February 10-20. Use DATEADD for partial-period preservation.-365 days instead of using SAMEPERIODLASTYEAR breaks on leap year boundaries. Always use built-in functions.Yes. All classic DAX time intelligence functions require a dedicated date table with unique values, no blanks, and contiguous dates spanning full calendar years. The table must be marked as a date table in Power BI Desktop. Using date columns from fact tables directly will produce incorrect results in multi-table models.
Identical results. TOTALYTD is syntactic sugar for CALCULATE with DATESYTD. The CALCULATE approach is recommended by SQLBI because it supports multiple filters, avoids the error-prone fiscal year-end string parameter, and follows a consistent pattern.
Not natively. Build a dual-calendar date table with Hijri columns via Power Query's Date.ToText with the "ar-SA" culture code, then use CALCULATE with explicit Hijri year/month filters instead of DATESYTD. This supports Hijri YTD and YOY while keeping Gregorian dates for standard functions.
Both shift date filter contexts, but handle partial periods differently. DATEADD preserves the original granularity — March 10-20 shifted by -1 month returns February 10-20. PARALLELPERIOD always returns complete periods — the same shift returns all of February (1-28/29). Use DATEADD for same-range comparisons, PARALLELPERIOD for full-period aggregations.
Both countries default to January 1 through December 31, aligned with the Gregorian calendar. Saudi Arabia adopted Gregorian fiscal reporting in 2016. Individual entities may use non-standard fiscal years — handled in DAX by passing the year-end date to DATESYTD(DateTable[Date], "6/30") for a July-to-June cycle.
The September 2025 preview introduced TOTALWTD, DATESWTD, STARTOFWEEK, ENDOFWEEK, PREVIOUSWEEK, NEXTWEEK, OPENINGBALANCEWEEK, and CLOSINGBALANCEWEEK. These require a calendar definition mapping week columns. As of March 2026, this remains in preview. For production models, use DATESINPERIOD with day-level intervals for week calculations.
Use CALCULATE with DATESINPERIOD to define a 12-month window: CALCULATE(SUM(Sales[Revenue]), DATESINPERIOD(DateTable[Date], MAX(DateTable[Date]), -12, MONTH)) gives the rolling 12-month total. Wrap with AVERAGEX over VALUES(DateTable[YearMonth]) for the average. Power BI also supports the MOVINGAVERAGE visual calculation, though it is scoped to individual visuals.
Ramadan shifts approximately 10-11 days earlier each Gregorian year, so SAMEPERIODLASTYEAR will not align the correct periods. Use the dual-calendar approach: filter on HijriMonth = 9 (Ramadan) for the current and prior Hijri years. This compares actual Ramadan periods regardless of Gregorian dates.
Microsoft Partner · Dubai
Your business intelligence partner for the GCC
Have a data challenge or a project in mind? Reach out and let's explore how we can help.
Clients we've worked with






