Forum Discussion
jaryszek
Super User
1 year agoHow to handle 53th week 445 calendar
Hi Guys, I am try to use this code: https://gorilla.bi/power-query/445-calendar/ let
// ===== USER PARAMETERS =====
StartDate = #date(2024, 1, 29), // Enter your fiscal calenda...
- 1 year ago
pls try
let // ===== USER PARAMETERS ===== StartDate = #date(2024, 1, 29), // Enter your fiscal calendar start date EndDate = #date(2030, 1, 25), // Enter your fiscal calendar end date Order445 = {4, 4, 5}, // Pattern for months in quarter: 4-4-5 // ===== 53RD WEEK LOGIC ===== // Function to determine if a fiscal year needs 53 weeks Needs53Weeks = (fiscalYearStart as date) as logical => let // Method 1: Check if fiscal year start falls on Thursday, Friday, or Saturday startDayOfWeek = Date.DayOfWeek(fiscalYearStart, Day.Monday), // 0=Monday, 6=Sunday needsExtra = startDayOfWeek >= 3 and startDayOfWeek <= 5 // Thu, Fri, Sat in needsExtra, // Alternative method: Check if adding 364 days overshoots the next fiscal year start // This is more accurate for custom fiscal calendars Needs53WeeksAlt = (fiscalYearStart as date, nextFiscalYearStart as date) as logical => let standardYearEnd = Date.AddDays(fiscalYearStart, 363), // 364 days - 1 daysBetween = Duration.Days(nextFiscalYearStart - fiscalYearStart), needsExtra = daysBetween > 364 in needsExtra, // ===== CREATE BASE DATE LIST ===== Dates = List.Dates(StartDate, Duration.Days(EndDate-StartDate)+1, #duration(1,0,0,0)), Source = Table.FromList(Dates, Splitter.SplitByNothing(), {"Date"}), AddDayIndex = Table.AddIndexColumn(Source, "DayIndex", 0, 1, Int64.Type), // ===== FISCAL YEAR CALCULATION WITH 53RD WEEK ===== BaseDaysInYear = List.Sum(Order445) * 4 * 7, // 364 days DaysInQuarter = List.Sum(Order445) * 7, // 91 days // Determine fiscal year boundaries considering 53rd week AddFiscalYearInfo = Table.AddColumn(AddDayIndex, "FiscalYearInfo", (row) => let currentDate = row[Date], yearsSinceStart = Number.IntegerDivide(row[DayIndex], BaseDaysInYear), // Calculate this fiscal year's start baseYearStart = Date.AddDays(StartDate, yearsSinceStart * BaseDaysInYear), // Check if this fiscal year needs 53 weeks needs53 = Needs53Weeks(baseYearStart), actualDaysInYear = if needs53 then BaseDaysInYear + 7 else BaseDaysInYear, // Recalculate year index with variable year lengths adjustedYearIndex = let totalDays = 0, yearIndex = 1, findYear = List.Generate( () => [year = 1, cumulativeDays = 0], each [cumulativeDays] <= row[DayIndex], each let yearStart = Date.AddDays(StartDate, [cumulativeDays]), yearNeeds53 = Needs53Weeks(yearStart), yearDays = if yearNeeds53 then BaseDaysInYear + 7 else BaseDaysInYear in [year = [year] + 1, cumulativeDays = [cumulativeDays] + yearDays] ), lastItem = List.Last(findYear) in lastItem[year] - 1, fiscalYear = Date.Year(StartDate) + adjustedYearIndex - 1 in [ YearIndex = adjustedYearIndex, FiscalYear = fiscalYear, Has53Weeks = needs53, DaysInThisYear = actualDaysInYear ], type record ), // Extract fiscal year info AddYearIndex = Table.AddColumn(AddFiscalYearInfo, "YearIndex", each [FiscalYearInfo][YearIndex], Int64.Type), AddFiscalYear = Table.AddColumn(AddYearIndex, "FiscalYear", each [FiscalYearInfo][FiscalYear], Int64.Type), AddHas53Weeks = Table.AddColumn(AddFiscalYear, "Has53Weeks", each [FiscalYearInfo][Has53Weeks], Logical.Type), AddDaysInYear = Table.AddColumn(AddHas53Weeks, "DaysInThisYear", each [FiscalYearInfo][DaysInThisYear], Int64.Type), // Calculate day of fiscal year (1-364 or 1-371) AddDayOfYear = Table.AddColumn(AddDaysInYear, "DayOfYear", (row) => let // Find the start of this fiscal year yearStartDayIndex = let findStart = List.Generate( () => [year = 1, cumulativeDays = 0], each [year] < row[YearIndex], each let yearStart = Date.AddDays(StartDate, [cumulativeDays]), yearNeeds53 = Needs53Weeks(yearStart), yearDays = if yearNeeds53 then BaseDaysInYear + 7 else BaseDaysInYear in [year = [year] + 1, cumulativeDays = [cumulativeDays] + yearDays] ), result = if List.Count(findStart) = 0 then 0 else List.Last(findStart)[cumulativeDays] in result, dayOfYear = row[DayIndex] - yearStartDayIndex + 1 in dayOfYear, Int64.Type ), // ===== QUARTER AND PERIOD CALCULATION ===== AddQuarterInfo = Table.AddColumn(AddDayOfYear, "QuarterInfo", (row) => let dayOfYear = row[DayOfYear], has53Weeks = row[Has53Weeks], // Standard quarter calculation quarterIndex = Number.IntegerDivide(dayOfYear-1, DaysInQuarter) + 1, dayOfQuarter = Number.Mod(dayOfYear-1, DaysInQuarter) + 1, // Adjust for 53rd week (add to Q4) adjustedQuarter = if has53Weeks and dayOfYear > (DaysInQuarter * 3) then [ QuarterIndex = 4, DayOfQuarter = dayOfYear - (DaysInQuarter * 3), DaysInThisQuarter = DaysInQuarter + 7 // Q4 gets extra week ] else if quarterIndex > 4 then // Safety check [ QuarterIndex = 4, DayOfQuarter = dayOfQuarter + DaysInQuarter, DaysInThisQuarter = DaysInQuarter + 7 ] else [ QuarterIndex = quarterIndex, DayOfQuarter = dayOfQuarter, DaysInThisQuarter = if quarterIndex = 4 and has53Weeks then DaysInQuarter + 7 else DaysInQuarter ] in adjustedQuarter, type record ), AddQuarterIndex = Table.AddColumn(AddQuarterInfo, "QuarterIndex", each [QuarterInfo][QuarterIndex], Int64.Type), AddDayOfQuarter = Table.AddColumn(AddQuarterIndex, "DayOfQuarter", each [QuarterInfo][DayOfQuarter], Int64.Type), AddDaysInQuarter = Table.AddColumn(AddDayOfQuarter, "DaysInThisQuarter", each [QuarterInfo][DaysInThisQuarter], Int64.Type), // ===== PERIOD CALCULATION WITH 53RD WEEK ===== AddPeriodInfo = Table.AddColumn(AddDaysInQuarter, "PeriodInfo", (row) => let dayOfQuarter = row[DayOfQuarter], quarterIndex = row[QuarterIndex], has53Weeks = row[Has53Weeks], order = Order445, // Calculate period within quarter periodOfQuarter = if dayOfQuarter <= order{0} * 7 then 1 else if dayOfQuarter <= (order{0} + order{1}) * 7 then 2 else 3, // For 53rd week: add to last period of last quarter (Period 12) isLastPeriodWith53 = quarterIndex = 4 and periodOfQuarter = 3 and has53Weeks, // Calculate days in this period daysInPeriod = let standardDays = order{periodOfQuarter-1} * 7 in if isLastPeriodWith53 then standardDays + 7 else standardDays, // Calculate day of period dayOfPeriod = let offset = if periodOfQuarter = 1 then 0 else if periodOfQuarter = 2 then order{0} * 7 else (order{0} + order{1}) * 7 in dayOfQuarter - offset, // Period number in fiscal year periodOfYear = (quarterIndex - 1) * 3 + periodOfQuarter in [ PeriodOfQuarter = periodOfQuarter, Period = periodOfYear, DayOfPeriod = dayOfPeriod, DaysInPeriod = daysInPeriod, IsLeapPeriod = isLastPeriodWith53 ], type record ), AddPeriodOfQuarter = Table.AddColumn(AddPeriodInfo, "PeriodOfQuarter", each [PeriodInfo][PeriodOfQuarter], Int64.Type), AddPeriod = Table.AddColumn(AddPeriodOfQuarter, "Period", each [PeriodInfo][Period], Int64.Type), AddDayOfPeriod = Table.AddColumn(AddPeriod, "DayOfPeriod", each [PeriodInfo][DayOfPeriod], Int64.Type), AddDaysInPeriod = Table.AddColumn(AddDayOfPeriod, "DaysInPeriod", each [PeriodInfo][DaysInPeriod], Int64.Type), AddIsLeapPeriod = Table.AddColumn(AddDaysInPeriod, "IsLeapPeriod", each [PeriodInfo][IsLeapPeriod], Logical.Type), // ===== WEEK CALCULATIONS ===== AddWeekIndex = Table.AddColumn(AddIsLeapPeriod, "WeekIndex", each Number.IntegerDivide([DayOfYear]-1, 7) + 1, Int64.Type), AddWeekOfQuarter = Table.AddColumn(AddWeekIndex, "WeekOfQuarter", each Number.Mod([WeekIndex]-1, if [Has53Weeks] and [QuarterIndex] = 4 then 14 else 13) + 1, Int64.Type), AddWeekOfPeriod = Table.AddColumn(AddWeekOfQuarter, "WeekOfPeriod", each Number.IntegerDivide([DayOfPeriod]-1, 7) + 1, Int64.Type), // ===== LABELS ===== AddQuarterLabel = Table.AddColumn(AddWeekOfPeriod, "QuarterLabel", each "Q" & Text.From([QuarterIndex])), AddPeriodLabel = Table.AddColumn(AddQuarterLabel, "PeriodLabel", each "P" & Text.PadStart(Text.From([Period]),2,"0")), AddWeekLabel = Table.AddColumn(AddPeriodLabel, "WeekLabel", each "W" & Text.PadStart(Text.From([WeekIndex]),2,"0")), // ===== DATE RANGES ===== // Week Start and End (assuming weeks start on Monday) AddWeekStart = Table.AddColumn(AddWeekLabel, "WeekStart", each Date.AddDays([Date], -Number.Mod(Date.DayOfWeek([Date], Day.Monday), 7))), AddWeekEnd = Table.AddColumn(AddWeekStart, "WeekEnd", each Date.AddDays([WeekStart], 6)), // Fiscal Year Start and End AddYearStart = Table.AddColumn(AddWeekEnd, "YearStart", each Date.AddDays([Date], -([DayOfYear]-1))), AddYearEnd = Table.AddColumn(AddYearStart, "YearEnd", each Date.AddDays([YearStart], [DaysInThisYear]-1)), // Fiscal Quarter Start and End AddQuarterStart = Table.AddColumn(AddYearEnd, "QuarterStart", each Date.AddDays([Date], -([DayOfQuarter]-1))), AddQuarterEnd = Table.AddColumn(AddQuarterStart, "QuarterEnd", each Date.AddDays([QuarterStart], [DaysInThisQuarter]-1)), // Period Start and End AddPeriodStart = Table.AddColumn(AddQuarterEnd, "PeriodStart", each Date.AddDays([Date], -([DayOfPeriod]-1))), AddPeriodEnd = Table.AddColumn(AddPeriodStart, "PeriodEnd", each Date.AddDays([PeriodStart], [DaysInPeriod]-1)), // Clean up and reorder columns RemoveHelperColumns = Table.RemoveColumns(AddPeriodEnd, {"DayIndex", "FiscalYearInfo", "QuarterInfo", "PeriodInfo"}), FinalTable = Table.SelectColumns( RemoveHelperColumns, { "Date", "FiscalYear", "YearStart", "YearEnd", "Has53Weeks", "DaysInThisYear", "QuarterIndex", "QuarterLabel", "QuarterStart", "QuarterEnd", "DaysInThisQuarter", "Period", "PeriodLabel", "PeriodStart", "PeriodEnd", "DaysInPeriod", "IsLeapPeriod", "WeekIndex", "WeekLabel", "WeekOfQuarter", "WeekOfPeriod", "WeekStart", "WeekEnd", "DayOfYear", "DayOfQuarter", "DayOfPeriod" } ) in FinalTable - 1 year ago
Calendars are immutable. There is no point trying to do this in Power Query or DAX. Use an external precomputed reference table.
Ahmedx
Super User
1 year agopls try
let
// ===== USER PARAMETERS =====
StartDate = #date(2024, 1, 29), // Enter your fiscal calendar start date
EndDate = #date(2030, 1, 25), // Enter your fiscal calendar end date
Order445 = {4, 4, 5}, // Pattern for months in quarter: 4-4-5
// ===== 53RD WEEK LOGIC =====
// Function to determine if a fiscal year needs 53 weeks
Needs53Weeks = (fiscalYearStart as date) as logical =>
let
// Method 1: Check if fiscal year start falls on Thursday, Friday, or Saturday
startDayOfWeek = Date.DayOfWeek(fiscalYearStart, Day.Monday), // 0=Monday, 6=Sunday
needsExtra = startDayOfWeek >= 3 and startDayOfWeek <= 5 // Thu, Fri, Sat
in needsExtra,
// Alternative method: Check if adding 364 days overshoots the next fiscal year start
// This is more accurate for custom fiscal calendars
Needs53WeeksAlt = (fiscalYearStart as date, nextFiscalYearStart as date) as logical =>
let
standardYearEnd = Date.AddDays(fiscalYearStart, 363), // 364 days - 1
daysBetween = Duration.Days(nextFiscalYearStart - fiscalYearStart),
needsExtra = daysBetween > 364
in needsExtra,
// ===== CREATE BASE DATE LIST =====
Dates = List.Dates(StartDate, Duration.Days(EndDate-StartDate)+1, #duration(1,0,0,0)),
Source = Table.FromList(Dates, Splitter.SplitByNothing(), {"Date"}),
AddDayIndex = Table.AddIndexColumn(Source, "DayIndex", 0, 1, Int64.Type),
// ===== FISCAL YEAR CALCULATION WITH 53RD WEEK =====
BaseDaysInYear = List.Sum(Order445) * 4 * 7, // 364 days
DaysInQuarter = List.Sum(Order445) * 7, // 91 days
// Determine fiscal year boundaries considering 53rd week
AddFiscalYearInfo = Table.AddColumn(AddDayIndex, "FiscalYearInfo",
(row) =>
let
currentDate = row[Date],
yearsSinceStart = Number.IntegerDivide(row[DayIndex], BaseDaysInYear),
// Calculate this fiscal year's start
baseYearStart = Date.AddDays(StartDate, yearsSinceStart * BaseDaysInYear),
// Check if this fiscal year needs 53 weeks
needs53 = Needs53Weeks(baseYearStart),
actualDaysInYear = if needs53 then BaseDaysInYear + 7 else BaseDaysInYear,
// Recalculate year index with variable year lengths
adjustedYearIndex =
let
totalDays = 0,
yearIndex = 1,
findYear = List.Generate(
() => [year = 1, cumulativeDays = 0],
each [cumulativeDays] <= row[DayIndex],
each
let
yearStart = Date.AddDays(StartDate, [cumulativeDays]),
yearNeeds53 = Needs53Weeks(yearStart),
yearDays = if yearNeeds53 then BaseDaysInYear + 7 else BaseDaysInYear
in [year = [year] + 1, cumulativeDays = [cumulativeDays] + yearDays]
),
lastItem = List.Last(findYear)
in lastItem[year] - 1,
fiscalYear = Date.Year(StartDate) + adjustedYearIndex - 1
in
[
YearIndex = adjustedYearIndex,
FiscalYear = fiscalYear,
Has53Weeks = needs53,
DaysInThisYear = actualDaysInYear
],
type record
),
// Extract fiscal year info
AddYearIndex = Table.AddColumn(AddFiscalYearInfo, "YearIndex", each [FiscalYearInfo][YearIndex], Int64.Type),
AddFiscalYear = Table.AddColumn(AddYearIndex, "FiscalYear", each [FiscalYearInfo][FiscalYear], Int64.Type),
AddHas53Weeks = Table.AddColumn(AddFiscalYear, "Has53Weeks", each [FiscalYearInfo][Has53Weeks], Logical.Type),
AddDaysInYear = Table.AddColumn(AddHas53Weeks, "DaysInThisYear", each [FiscalYearInfo][DaysInThisYear], Int64.Type),
// Calculate day of fiscal year (1-364 or 1-371)
AddDayOfYear = Table.AddColumn(AddDaysInYear, "DayOfYear",
(row) =>
let
// Find the start of this fiscal year
yearStartDayIndex =
let
findStart = List.Generate(
() => [year = 1, cumulativeDays = 0],
each [year] < row[YearIndex],
each
let
yearStart = Date.AddDays(StartDate, [cumulativeDays]),
yearNeeds53 = Needs53Weeks(yearStart),
yearDays = if yearNeeds53 then BaseDaysInYear + 7 else BaseDaysInYear
in [year = [year] + 1, cumulativeDays = [cumulativeDays] + yearDays]
),
result = if List.Count(findStart) = 0 then 0 else List.Last(findStart)[cumulativeDays]
in result,
dayOfYear = row[DayIndex] - yearStartDayIndex + 1
in dayOfYear,
Int64.Type
),
// ===== QUARTER AND PERIOD CALCULATION =====
AddQuarterInfo = Table.AddColumn(AddDayOfYear, "QuarterInfo",
(row) =>
let
dayOfYear = row[DayOfYear],
has53Weeks = row[Has53Weeks],
// Standard quarter calculation
quarterIndex = Number.IntegerDivide(dayOfYear-1, DaysInQuarter) + 1,
dayOfQuarter = Number.Mod(dayOfYear-1, DaysInQuarter) + 1,
// Adjust for 53rd week (add to Q4)
adjustedQuarter = if has53Weeks and dayOfYear > (DaysInQuarter * 3) then
[
QuarterIndex = 4,
DayOfQuarter = dayOfYear - (DaysInQuarter * 3),
DaysInThisQuarter = DaysInQuarter + 7 // Q4 gets extra week
]
else if quarterIndex > 4 then // Safety check
[
QuarterIndex = 4,
DayOfQuarter = dayOfQuarter + DaysInQuarter,
DaysInThisQuarter = DaysInQuarter + 7
]
else
[
QuarterIndex = quarterIndex,
DayOfQuarter = dayOfQuarter,
DaysInThisQuarter = if quarterIndex = 4 and has53Weeks then DaysInQuarter + 7 else DaysInQuarter
]
in adjustedQuarter,
type record
),
AddQuarterIndex = Table.AddColumn(AddQuarterInfo, "QuarterIndex", each [QuarterInfo][QuarterIndex], Int64.Type),
AddDayOfQuarter = Table.AddColumn(AddQuarterIndex, "DayOfQuarter", each [QuarterInfo][DayOfQuarter], Int64.Type),
AddDaysInQuarter = Table.AddColumn(AddDayOfQuarter, "DaysInThisQuarter", each [QuarterInfo][DaysInThisQuarter], Int64.Type),
// ===== PERIOD CALCULATION WITH 53RD WEEK =====
AddPeriodInfo = Table.AddColumn(AddDaysInQuarter, "PeriodInfo",
(row) =>
let
dayOfQuarter = row[DayOfQuarter],
quarterIndex = row[QuarterIndex],
has53Weeks = row[Has53Weeks],
order = Order445,
// Calculate period within quarter
periodOfQuarter =
if dayOfQuarter <= order{0} * 7 then 1
else if dayOfQuarter <= (order{0} + order{1}) * 7 then 2
else 3,
// For 53rd week: add to last period of last quarter (Period 12)
isLastPeriodWith53 = quarterIndex = 4 and periodOfQuarter = 3 and has53Weeks,
// Calculate days in this period
daysInPeriod =
let
standardDays = order{periodOfQuarter-1} * 7
in
if isLastPeriodWith53 then standardDays + 7 else standardDays,
// Calculate day of period
dayOfPeriod =
let
offset = if periodOfQuarter = 1 then 0
else if periodOfQuarter = 2 then order{0} * 7
else (order{0} + order{1}) * 7
in dayOfQuarter - offset,
// Period number in fiscal year
periodOfYear = (quarterIndex - 1) * 3 + periodOfQuarter
in
[
PeriodOfQuarter = periodOfQuarter,
Period = periodOfYear,
DayOfPeriod = dayOfPeriod,
DaysInPeriod = daysInPeriod,
IsLeapPeriod = isLastPeriodWith53
],
type record
),
AddPeriodOfQuarter = Table.AddColumn(AddPeriodInfo, "PeriodOfQuarter", each [PeriodInfo][PeriodOfQuarter], Int64.Type),
AddPeriod = Table.AddColumn(AddPeriodOfQuarter, "Period", each [PeriodInfo][Period], Int64.Type),
AddDayOfPeriod = Table.AddColumn(AddPeriod, "DayOfPeriod", each [PeriodInfo][DayOfPeriod], Int64.Type),
AddDaysInPeriod = Table.AddColumn(AddDayOfPeriod, "DaysInPeriod", each [PeriodInfo][DaysInPeriod], Int64.Type),
AddIsLeapPeriod = Table.AddColumn(AddDaysInPeriod, "IsLeapPeriod", each [PeriodInfo][IsLeapPeriod], Logical.Type),
// ===== WEEK CALCULATIONS =====
AddWeekIndex = Table.AddColumn(AddIsLeapPeriod, "WeekIndex", each Number.IntegerDivide([DayOfYear]-1, 7) + 1, Int64.Type),
AddWeekOfQuarter = Table.AddColumn(AddWeekIndex, "WeekOfQuarter", each Number.Mod([WeekIndex]-1, if [Has53Weeks] and [QuarterIndex] = 4 then 14 else 13) + 1, Int64.Type),
AddWeekOfPeriod = Table.AddColumn(AddWeekOfQuarter, "WeekOfPeriod", each Number.IntegerDivide([DayOfPeriod]-1, 7) + 1, Int64.Type),
// ===== LABELS =====
AddQuarterLabel = Table.AddColumn(AddWeekOfPeriod, "QuarterLabel", each "Q" & Text.From([QuarterIndex])),
AddPeriodLabel = Table.AddColumn(AddQuarterLabel, "PeriodLabel", each "P" & Text.PadStart(Text.From([Period]),2,"0")),
AddWeekLabel = Table.AddColumn(AddPeriodLabel, "WeekLabel", each "W" & Text.PadStart(Text.From([WeekIndex]),2,"0")),
// ===== DATE RANGES =====
// Week Start and End (assuming weeks start on Monday)
AddWeekStart = Table.AddColumn(AddWeekLabel, "WeekStart", each Date.AddDays([Date], -Number.Mod(Date.DayOfWeek([Date], Day.Monday), 7))),
AddWeekEnd = Table.AddColumn(AddWeekStart, "WeekEnd", each Date.AddDays([WeekStart], 6)),
// Fiscal Year Start and End
AddYearStart = Table.AddColumn(AddWeekEnd, "YearStart", each Date.AddDays([Date], -([DayOfYear]-1))),
AddYearEnd = Table.AddColumn(AddYearStart, "YearEnd", each Date.AddDays([YearStart], [DaysInThisYear]-1)),
// Fiscal Quarter Start and End
AddQuarterStart = Table.AddColumn(AddYearEnd, "QuarterStart", each Date.AddDays([Date], -([DayOfQuarter]-1))),
AddQuarterEnd = Table.AddColumn(AddQuarterStart, "QuarterEnd", each Date.AddDays([QuarterStart], [DaysInThisQuarter]-1)),
// Period Start and End
AddPeriodStart = Table.AddColumn(AddQuarterEnd, "PeriodStart", each Date.AddDays([Date], -([DayOfPeriod]-1))),
AddPeriodEnd = Table.AddColumn(AddPeriodStart, "PeriodEnd", each Date.AddDays([PeriodStart], [DaysInPeriod]-1)),
// Clean up and reorder columns
RemoveHelperColumns = Table.RemoveColumns(AddPeriodEnd, {"DayIndex", "FiscalYearInfo", "QuarterInfo", "PeriodInfo"}),
FinalTable = Table.SelectColumns(
RemoveHelperColumns,
{
"Date", "FiscalYear", "YearStart", "YearEnd", "Has53Weeks", "DaysInThisYear",
"QuarterIndex", "QuarterLabel", "QuarterStart", "QuarterEnd", "DaysInThisQuarter",
"Period", "PeriodLabel", "PeriodStart", "PeriodEnd", "DaysInPeriod", "IsLeapPeriod",
"WeekIndex", "WeekLabel", "WeekOfQuarter", "WeekOfPeriod", "WeekStart", "WeekEnd",
"DayOfYear", "DayOfQuarter", "DayOfPeriod"
}
)
in
FinalTable