Holidays

South Africa Public Holidays Calculator

South Africa's public holidays for any year, calculated live from the actual rules, including the Sunday-to-Monday shift.

The Sunday-to-Monday rule

Under South Africa's Public Holidays Act, whenever a public holiday falls on a Sunday, the following Monday automatically becomes a public holiday too — a simpler, one-directional version of the US federal observed-date system, since it only ever shifts forward and only triggers on a Sunday collision specifically, not a Saturday one.

A calendar shaped by a specific history

Several of the fixed dates on this list — Human Rights Day (March 21, the Sharpeville massacre anniversary), Freedom Day (April 27, the date of the first democratic elections in 1994), and Reconciliation Day (December 16) — were deliberately chosen after apartheid ended to mark specific events in that transition, making South Africa's calendar unusually tied to a single, recent, well-documented period of national history compared to most countries' more diffusely historical holidays.

Related

Related tools

function computeEaster(year){ const a = year % 19; const b = Math.floor(year/100); const c = year % 100; const d = Math.floor(b/4); const e = b % 4; const f = Math.floor((b+8)/25); const g = Math.floor((b-f+1)/3); const h = (19*a + b - d - g + 15) % 30; const i = Math.floor(c/4); const k = c % 4; const l = (32 + 2*e + 2*i - h - k) % 7; const m = Math.floor((a + 11*h + 22*l)/451); const month = Math.floor((h + l - 7*m + 114)/31); const day = ((h + l - 7*m + 114) % 31) + 1; return new Date(Date.UTC(year, month-1, day)); } function southAfricaHolidays(year){ function sundayShift(date){ if(date.getUTCDay() === 0){ const d = new Date(date); d.setUTCDate(d.getUTCDate()+1); return d; } return date; } const easter = computeEaster(year); const goodFriday = new Date(easter); goodFriday.setUTCDate(easter.getUTCDate()-2); const familyDay = new Date(easter); familyDay.setUTCDate(easter.getUTCDate()+1); const raw = [ ['New Year\'s Day', new Date(Date.UTC(year,0,1))], ['Human Rights Day', new Date(Date.UTC(year,2,21))], ['Good Friday', goodFriday], ['Family Day (Easter Monday)', familyDay], ['Freedom Day', new Date(Date.UTC(year,3,27))], ['Workers\' Day', new Date(Date.UTC(year,4,1))], ['Youth Day', new Date(Date.UTC(year,5,16))], ['National Women\'s Day', new Date(Date.UTC(year,7,9))], ['Heritage Day', new Date(Date.UTC(year,8,24))], ['Day of Reconciliation', new Date(Date.UTC(year,11,16))], ['Christmas Day', new Date(Date.UTC(year,11,25))], ['Day of Goodwill', new Date(Date.UTC(year,11,26))], ]; return raw.map(([name,date]) => ({name, date, observed: sundayShift(date)})); } const now = new Date(); for(let y = now.getFullYear()-1; y <= now.getFullYear()+3; y++){ const opt = document.createElement('option'); opt.value = y; opt.textContent = y; if(y === now.getFullYear()) opt.selected = true; document.getElementById('hlYear').appendChild(opt); } const yearSelect = document.getElementById('hlYear'); const table = document.getElementById('hlTable'); function fmt(d){ return d.toLocaleDateString('en-US',{weekday:'short', month:'long', day:'numeric'}); } function render(){ const year = parseInt(yearSelect.value,10); const rows = southAfricaHolidays(year); table.innerHTML = rows.map(r => { let obsHtml = ''; if(r.observed && r.observed.getTime() !== r.date.getTime()){ obsHtml = ` (observed ${fmt(r.observed)})`; } return `
${r.name}${fmt(r.date)}${obsHtml}
`; }).join(''); } yearSelect.addEventListener('change', render); render();