Tanggal Merah
An Indonesian holiday and leave planner that shows whether collective leave eats into your 12 days

- leave days left if your employer deducts
- 12 → 4
- 2026 holidays and collective leave days, each cited
- 25
- leave plans, checked against every combination
- Exact
- employment statuses, each with its own rule
- 3
On this page
The problem
Indonesian office workers plan their annual leave around the public holidays set each year in a joint decree of three ministers. That decree creates two kinds of day off. National holidays (libur nasional) are free. Collective leave days (cuti bersama) can be charged against the 12-day annual leave entitlement, but only for some people.
For 2026 there are 8 collective leave days. A private-sector worker whose company closes and deducts them is left with 4 days of leave. A colleague at a company that stays open keeps 12. News reports on the rule contradict each other, and at least one reversed it entirely. Most people find out in November, when they try to book a trip. Every other holiday calendar shows all these days as one kind of "holiday" and never says what they cost.
What I built
Your employment status decides the answer
I made employment status the first input: civil servant, private sector with deduction, and private sector without. Each branch cites the regulation it comes from. The landing page shows four status cards. Three leave you 12 days and one leaves you 4. On the calendar, the app marks exactly which collective leave days a deducting employer charged.
Holidays come from the decree, never from a formula
Idul Fitri, Nyepi, Waisak and Imlek can all be estimated from the moon or a calendar. The official holiday is whatever the decree says, and the decree defers the Islamic dates to a separate Ministry of Religious Affairs ruling. So I transcribe each year's decree and calculate no religious date anywhere. A year without a published decree gets a clear refusal that names the gap. Being confidently wrong about someone's day off is the failure that matters most here.
Every holiday carries its source
Each holiday records its date, type, decree number and signing date. The build fails on a holiday with no citation, a duplicate date, or a leftover placeholder. Where sources disagree about the collective leave rule, a rules page shows both readings with their sources. It also states what the rejected reading would do to your leave if it were true.
The leave planner finds the best days exactly
A single workday between a holiday and a weekend turns one leave day into a four-day break. Spotting these across twelve months by eye is tedious and easy to get wrong. The planner picks the best days for your budget, and I checked it against a slow method that tries every combination. That check caught a bug. Planning for the longest single break needs a different method from planning for the most total days off.
A calendar someone who has never heard the rule can follow
Once the maths was right, I rebuilt the interface for a reader who doesn't know the rule exists. A worked example with real dates comes before any control. Each citation sits on the card that applies it. Months became keyboard-navigable grids, and the page announces the result when it changes.
Result
Tanggal Merah is live and public, in Indonesian and English, and works offline after the first load. The year view is laid out like an Indonesian wall calendar, with national holidays in red and collective leave in amber. Toggle a leave day and two blocks join into one bar. It also shows what each extra leave day buys and which holidays the weekend swallows, for five- and six-day weeks. It covers 2026: 17 national holidays and 8 collective leave days, each cited. The site says it is a personal project and not employment-law advice, and that company policy governs collective leave in the private sector. I built it over 12 and 13 August 2026.
Under the hoodTechnical detail for engineers
- No
Dateobjects in the engine. Days are integer day numbers, week position is arithmetic, and the year is always an explicit argument. The UI converts at the boundary. - Decree data lives in
data/skb/.pnpm rules:validateruns first and alone in CI, before typecheck, lint, tests and build.data/skb/2026.jsonis flaggedperluVerifikasi, with decree numbers recorded asBELUM DIVERIFIKASIand the checks listed inUPDATING.md. data/contradictions/holds the competing readings of the cuti bersama rule, which value the app uses, and why.- The optimiser enumerates gaps between fixed off-blocks, costs each in workdays and selects under budget with a DP.
lib/optimise/brute.ts, a twenty-line oracle never imported outside tests, was committed first. The longest-stretch objective can't reuse the DP withmaxswapped in (right number, wrong plan), so it uses a contiguous scan with its own oracle. - "1 day → 4 days off" measures contiguity. Days gained per day spent is always 1.0; one commit exists to correct that wording.
- The marginal curve reruns the optimiser at every budget. It isn't monotone: a two-day bridge is unaffordable at a budget of one, so day 2 can be worth more than day 1. Hand-drawn SVG.
- A test asserts the per-day deduction marks sum to the ledger total across every year, work pattern and status.
- Amber measures 2.48:1 on the background, so the PNG export uses text-safe variants. PNG is drawn straight onto a canvas with no DOM rasteriser. ICS export and full state in the URL hash.
- Zod was moved to devDependencies, since validation is build-time only. Three runtime dependencies, no date, calendar or holiday library.
- About 9,150 lines, 134 tests in 16 files, 70 commits (14 accessibility, 13 design, 7 pedagogy).
Screenshots
Hiring, or building something similar?
I'm open to full-time roles and select freelance work.