日本語 · English

Defining a 4-4-5 fiscal calendar — the 53rd week falls out automatically

Translated from the canonical Japanese page recipes/4-4-5-calendar.md.

The 4-4-5 fiscal calendar used in retail and manufacturing (each quarter split into periods of 4, 4, and 5 weeks) is a calendar with no “months”, so every month-based recurrence vocabulary fails at once. In Kairos the calendar itself is a derived premise — and the notorious 53rd-week carry rule never even has to be written.

What happens elsewhere

Writing it in Kairos

Take the period heads — “Mondays of ISO weeks 1, 5, 9, 14, …, 48” — as a marker stream and cut periods with segmentBy, deriving from the standard ISOWeek premise:

# eval: 2025-12-01..2027-03-01
premise R445 = ISOWeek with {
  periodStart = isoWeekStart |> filter(d =>
    ((isoWeekNo(d) - 1) mod 13 == 0 or (isoWeekNo(d) - 1) mod 13 == 4 or (isoWeekNo(d) - 1) mod 13 == 8)
    and isoWeekNo(d) <= 48)
  period = day |> segmentBy(periodStart, edges: clip, empties: error)
}
premise JPR { calendar-system: R445; tz: "Asia/Tokyo"; wkst: Mon }
@JPR
everyDay |> within(period) |> first
#=> 2025-12-29 2026-01-26 2026-02-23 2026-03-30 2026-04-27 2026-05-25
#=> 2026-06-29 2026-07-27 2026-08-24 2026-09-28 2026-10-26 2026-11-23
#=> 2027-01-04 2027-02-01

ISO year 2026 has 53 weeks — the final period P12 automatically stretches to six weeks (11/23 through 2027-01-03, absorbing W49–W53), and the next year restarts normally from W01 (2027-01-04). The carry rule (NRF’s “add it to the last period”) is nowhere in the code — it falls out of the shape of the definition, “period heads only up to W48”. Instead of enumerating rules, you define the structure of the calendar and the correct edges emerge.

Once the periods exist, “3 business days before period-end” and “first business day of the period” use exactly the same vocabulary as Gregorian months (within(period), roll, shift).

Try it in your browser

Run it in the Playground — change mod 13 == 0/4/8 and you get the 4-5-4 and 5-4-4 variants.