Business Professionals
Power BI | Power Pivot | Power Query | DAX
Cloud Flows | RPA | AI Builder | Copilot
60+ Formulas | Data Stories | Advanced Reporting & Modeling
VB Programming | Report Automation |
MS-Office Automation
Techno-Business Professionals
Power BI | Power Query | Advanced DAX | SQL - Query &
Programming
Microsoft Fabric | Power BI | Power Query | Advanced DAX |
SQL - Query & Programming
Power BI | Power Apps | Power Automate | Copilot Studio | Power Pages | Dataverse
Microsoft Power Apps | Microsoft Power Automate
Power BI | Adv. DAX | SQL (Query & Programming) |
VBA | Python | Web Scrapping | API Integration
Power BI | Power Apps | Power Automate |
SQL (Query & Programming)
Power BI | Adv. DAX | Power Apps | Power Automate |
SQL (Query & Programming) | VBA | Python | Web Scrapping | API Integration
Power Apps | Power Automate | SQL | VBA | Python |
Web Scraping | RPA | API Integration
Technology Professionals
Power BI | DAX | SQL | ETL with SSIS | SSAS | VBA | Python
Power BI | SQL | Azure Data Lake | Synapse Analytics |
Data Factory | Databricks | Power Apps | Power Automate |
Azure Analysis Services
Microsoft Fabric | Power BI | SQL | Lakehouse |
Data Factory (Pipelines) | Dataflows Gen2 | KQL | Delta Tables | Power Apps | Power Automate
Power BI | Power Apps | Power Automate | SQL | VBA | Python | API Integration
Power BI | Advanced DAX | Databricks | SQL | Lakehouse Architecture
Business Professionals
Power BI | Power Pivot | Power Query | DAX
Cloud Flows | RPA | AI Builder | Copilot
60+ Formulas | Data Stories | Advanced Reporting & Modeling
VB Programming | Report Automation |
MS-Office Automation
Techno-Business Professionals
Power BI | Power Query | Advanced DAX | SQL - Query &
Programming
Microsoft Fabric | Power BI | Power Query | Advanced DAX |
SQL - Query & Programming
Power BI | Power Apps | Power Automate | Copilot Studio | Power Pages | Dataverse
Microsoft Power Apps | Microsoft Power Automate
Power BI | Adv. DAX | SQL (Query & Programming) |
VBA | Web Scrapping | API Integration
Power BI | Power Apps | Power Automate |
SQL (Query & Programming)
Power BI | Adv. DAX | Power Apps | Power Automate |
SQL (Query & Programming) | VBA | Web Scrapping | API Integration
Power Apps | Power Automate | SQL | VBA |
Web Scraping | RPA | API Integration
Technology Professionals
Power BI | DAX | SQL | ETL with SSIS | SSAS | VBA
Power BI | SQL | Azure Data Lake | Synapse Analytics |
Data Factory | Azure Analysis Services
Microsoft Fabric | Power BI | SQL | Lakehouse |
Data Factory (Pipelines) | Dataflows Gen2 | KQL | Delta Tables
Power BI | Power Apps | Power Automate | SQL | VBA | API Integration
Power BI | Advanced DAX | Databricks | SQL | Lakehouse Architecture
Power BI’s built‑in time intelligence works well until finance asks for fiscal year views, operations wants 4‑4‑5 weeks, and product wants metrics by “campaign periods” that don’t align with any calendar. Then your measures start disagreeing with the ERP and you spend days chasing why totals don’t match.
This article walks through a realistic setup where you need fiscal calendars, non‑standard week definitions, and irregular periods in the same model, and shows how to structure your date table and DAX so that everything stays consistent and debuggable.
You’re building a Power BI model for a mid‑size business with:
Symptoms you’re seeing:
TOTALYTD and SAMEPERIODLASTYEAR don’t match finance’s fiscal reports.We’ll fix this by:
Power BI’s built‑in auto date/time is not designed for fiscal or custom calendars. For advanced time intelligence you should:
Key properties of the date table:
Here’s a robust Power Query script for a date table covering the last 5 years and the next 2 years from refresh date:
let
Today = Date.From(DateTimeZone.UtcNow()),
StartDate = Date.AddYears(Today, -5),
EndDate = Date.AddYears(Today, 2),
DateList = List.Dates(
StartDate,
Duration.Days(EndDate - StartDate) + 1,
#duration(1, 0, 0, 0)
),
DateTable = Table.FromList(DateList, Splitter.SplitByNothing(), {"Date"}, null, ExtraValues.Error),
Typed = Table.TransformColumnTypes(DateTable, {{"Date", type date}}),
// Basic calendar columns
AddYear = Table.AddColumn(Typed, "Year", each Date.Year([Date]), Int64.Type),
AddMonthNum = Table.AddColumn(AddYear, "MonthNumber", each Date.Month([Date]), Int64.Type),
AddDayOfWeek = Table.AddColumn(AddMonthNum, "DayOfWeek", each Date.DayOfWeek([Date], Day.Sunday), Int64.Type),
AddDayOfWeekName = Table.AddColumn(AddDayOfWeek, "DayOfWeekName", each Date.DayOfWeekName([Date]), type text),
AddMonthName = Table.AddColumn(AddDayOfWeekName, "MonthName", each Date.MonthName([Date]), type text)
in
AddMonthName
After loading this table:
Date column.We’ll extend this table for fiscal, custom weeks, and irregular periods.
Finance wants:
Power BI’s standard time intelligence (e.g., TOTALYTD) assumes calendar year unless you pass a year‑end parameter. For fiscal calendars, you need explicit fiscal columns.
We’ll assume fiscal year starts on 1 April and ends on 31 March.
let
Source = AddMonthName,
FiscalYearStartMonth = 4,
AddFiscalYear = Table.AddColumn(
Source,
"FiscalYear",
each if Date.Month([Date]) >= FiscalYearStartMonth
then Date.Year([Date]) + 1
else Date.Year([Date]),
Int64.Type
),
AddFiscalMonthNumber = Table.AddColumn(
AddFiscalYear,
"FiscalMonthNumber",
each let
m = Date.Month([Date])
in
if m >= FiscalYearStartMonth
then m - FiscalYearStartMonth + 1
else m + (12 - FiscalYearStartMonth + 1),
Int64.Type
),
AddFiscalMonthName = Table.AddColumn(
AddFiscalMonthNumber,
"FiscalMonthName",
each "F" & Text.PadStart(Text.From([FiscalMonthNumber]), 2, "0"),
type text
)
in
AddFiscalMonthName
This gives you:
FiscalYear (e.g., 2027 representing FY 2026–2027).FiscalMonthNumber (1–12 starting in April).FiscalMonthName (F01–F12).You can still use built‑in functions, but you must pass the right columns.
Example: year‑to‑date on a fiscal year ending in March.
Sales := SUM ( 'FactSales'[SalesAmount] )
Sales FYTD :=
TOTALYTD (
[Sales],
'Date'[Date],
"03-31"
)
Key points:
TOTALYTD is a text date representing fiscal year end (month‑day). It must be valid for the calendar year.TOTALYTD aligns with your fiscal year starting in April.For comparisons like fiscal year‑over‑year:
Sales FY :=
CALCULATE (
[Sales],
ALL ( 'Date' ),
VALUES ( 'Date'[FiscalYear] )
)
Sales FY YoY :=
VAR CurrentFY = MAX ( 'Date'[FiscalYear] )
VAR PriorFY = CurrentFY - 1
RETURN
CALCULATE (
[Sales FY],
FILTER (
ALL ( 'Date' ),
'Date'[FiscalYear] = PriorFY
)
)
This uses your FiscalYear column directly, avoiding assumptions about calendar years.
Year and a measure uses FiscalYear, you can get unexpected partial totals. Keep visuals and measures aligned to one calendar per visual.SAMEPERIODLASTYEAR on calendar year but expecting fiscal behaviour: For fiscal comparisons, base logic on FiscalYear and FiscalMonthNumber, not Year and MonthNumber.Operations want 4‑4‑5 weeks ending Saturday. Default week functions (WEEKNUM, ISO week) don’t match.
The safest pattern is:
There are many variants of 4‑4‑5 (some years have 53 weeks, some companies shift the extra week). The reliable way is:
WeekKey (e.g., 2027-W01 or a numeric key like 202701).WeekStartDate.WeekEndDate.WeekInQuarter (1–13).RetailQuarter.RetailYear.Then join it to the date table in Power Query.
Example of merging a RetailWeeks table into the date table:
let
DateTable = AddFiscalMonthName,
RetailWeeks = Excel.CurrentWorkbook(){[Name="RetailWeeks"]}[Content],
TypedWeeks = Table.TransformColumnTypes(
RetailWeeks,
{
{"WeekStartDate", type date},
{"WeekEndDate", type date},
{"WeekKey", type text},
{"RetailYear", Int64.Type},
{"RetailQuarter", Int64.Type},
{"WeekInQuarter", Int64.Type}
}
),
// Create one row per date in each retail week
AddDates = Table.AddColumn(
TypedWeeks,
"Dates",
each List.Dates(
[WeekStartDate],
Duration.Days([WeekEndDate] - [WeekStartDate]) + 1,
#duration(1, 0, 0, 0)
)
),
ExpandDates = Table.ExpandListColumn(AddDates, "Dates"),
RenameDate = Table.RenameColumns(ExpandDates, {{"Dates", "Date"}}),
TypedDates = Table.TransformColumnTypes(RenameDate, {{"Date", type date}}),
// Join week attributes onto each date
JoinWeeks = Table.Join(
DateTable,
"Date",
TypedDates,
"Date",
JoinKind.LeftOuter
)
in
JoinWeeks
This ensures every date knows which retail week it belongs to.
Now you can build week‑based measures using WeekKey.
Sales Week :=
CALCULATE (
[Sales],
REMOVEFILTERS ( 'Date' ),
VALUES ( 'Date'[WeekKey] )
)
Sales Week Rolling 4 Weeks :=
VAR CurrentIndex = MAX ( 'Date'[WeekIndex] )
RETURN
CALCULATE (
[Sales],
FILTER (
ALL ( 'Date' ),
'Date'[WeekIndex] <= CurrentIndex
&& 'Date'[WeekIndex] > CurrentIndex - 4
)
)
The rolling measure uses a numeric WeekIndex column that orders weeks chronologically (e.g., 1, 2, 3, … across years).
WEEKNUM or ISO week with 4‑4‑5 expectations: Those functions don’t know about 4‑4‑5 rules. Always drive logic from your WeekKey/WeekIndex.Marketing runs campaigns that:
If you try to bake these directly into the main date table, you’ll quickly hit issues:
The safe pattern is:
Create a Campaign dimension with at least:
CampaignID.CampaignName.StartDate.EndDate.Then create a bridge table CampaignDate with:
CampaignID.Date.This table contains one row per campaign per date in that campaign.
You can build CampaignDate in Power Query:
let
Campaigns = Excel.CurrentWorkbook(){[Name="Campaigns"]}[Content],
TypedCampaigns = Table.TransformColumnTypes(
Campaigns,
{
{"CampaignID", Int64.Type},
{"CampaignName", type text},
{"StartDate", type date},
{"EndDate", type date}
}
),
AddDateList = Table.AddColumn(
TypedCampaigns,
"Dates",
each List.Dates(
[StartDate],
Duration.Days([EndDate] - [StartDate]) + 1,
#duration(1, 0, 0, 0)
)
),
ExpandDates = Table.ExpandListColumn(AddDateList, "Dates"),
RenameDate = Table.RenameColumns(ExpandDates, {{"Dates", "Date"}}),
KeepColumns = Table.SelectColumns(RenameDate, {"CampaignID", "Date"}),
Typed = Table.TransformColumnTypes(KeepColumns, {{"Date", type date}})
in
Typed
Relationships in the model:
Date[Date] → CampaignDate[Date] (one‑to‑many).Campaign[CampaignID] → CampaignDate[CampaignID] (one‑to‑many).Now you can filter facts by campaigns using DAX.
Assume FactSales has a relationship to Date on Date[Date].
Sales by campaign:
Sales Campaign :=
VAR CampaignDates =
CALCULATETABLE (
VALUES ( CampaignDate[Date] ),
ALL ( 'Date' )
)
RETURN
CALCULATE (
[Sales],
KEEPFILTERS ( CampaignDates )
)
Explanation:
Campaign.CampaignDate (by CampaignID).Sales Campaign collects the dates for the current campaign and applies them as filters on Date.This handles overlapping campaigns correctly: a date can belong to multiple campaigns via CampaignDate, but the measure only applies the dates relevant to the current campaign filter context.
You can safely combine campaigns with fiscal and week logic because:
Example: campaign sales per fiscal month:
Sales Campaign FiscalMonth :=
CALCULATE (
[Sales Campaign],
VALUES ( 'Date'[FiscalYear] ),
VALUES ( 'Date'[FiscalMonthNumber] )
)
As long as the relationships are set up correctly, this respects both campaign windows and fiscal month boundaries.
With fiscal years, custom weeks, and irregular periods in play, models can get messy fast. A few practical patterns help keep things under control:
RetailWeeks, CampaignDate) instead.FiscalYear, RetailYear, CalendarYear instead of just Year when multiple calendars exist.WeekIndex, PeriodID.[Sales]).When you need advanced time intelligence in Power BI—fiscal calendars, custom weeks, and irregular periods—stop relying on the default date logic and instead design a single, explicit date table plus small helper tables for special calendars. Once every date knows its fiscal year, week period, and campaign memberships, your DAX measures become simpler, your totals line up with source systems, and adding the next “special period” request is a modeling task, not a rewrite.
This article reflects the shift from relying on built‑in calendar logic to explicitly modeling fiscal years, custom weeks, and irregular periods in Power BI, which matters most for teams reconciling analytics with finance, retail, and marketing source systems.
Professionals who want to apply these patterns to their own data can explore Excelgoodies' Power BI Reporting programme - taught live by instructors, with certification awarded once a real project is running at work.
Insights compiled through ongoing industry research and discussions within the Excelgoodies Analytics Community.
Power BI
New
Next Batches Now Live
Power BI
SQL
Power Apps
Power Automate
Microsoft Fabrics
Azure Data Engineering