diff --git a/src/Countries/SouthAfrica.php b/src/Countries/SouthAfrica.php new file mode 100644 index 00000000..18ee55ec --- /dev/null +++ b/src/Countries/SouthAfrica.php @@ -0,0 +1,64 @@ + '01-01', + 'Human Rights Day' => '03-21', + 'Freedom Day' => '04-27', + 'Workers\' Day' => '05-01', + 'Youth Day' => '06-16', + 'National Women\'s Day' => '08-09', + 'Heritage Day' => '09-24', + 'Day of Reconciliation' => '12-16', + 'Christmas Day' => '12-25', + 'Day of Goodwill' => '12-26', + ]; + + foreach ($holidays as $name => $date) { + $holidayDate = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}"); + assert($holidayDate instanceof CarbonImmutable); + + $holidays[$name] = $holidayDate->setTimezone($this->timezone); + + // The Public Holidays Act (Act No 36 of 1994) states that whenever a public holiday falls on a Sunday, the Monday following it will be a public holiday. + // https://www.gov.za/documents/public-holidays-act + if ( + $holidayDate->isSunday() && + !in_array($holidayDate->addDay()->format('m-d'), $holidays, true) // Check that the Monday is not already a holiday + ) { + $holidays[$name . ' Observed'] = $holidayDate->addDay(); + } + } + + return array_merge($holidays, $this->variableHolidays($year)); + } + + /** @return array */ + protected function variableHolidays(int $year): array + { + $easter = CarbonImmutable::createFromTimestamp(easter_date($year)) + ->setTimezone($this->timezone); + + return [ + 'Good Friday' => $easter->subDays(2), + 'Family Day' => $easter->addDay(), + ]; + } +} diff --git a/tests/.pest/snapshots/Countries/SouthAfricaTest/it_can_calculate_south_africa_holidays.snap b/tests/.pest/snapshots/Countries/SouthAfricaTest/it_can_calculate_south_africa_holidays.snap new file mode 100644 index 00000000..4bef9984 --- /dev/null +++ b/tests/.pest/snapshots/Countries/SouthAfricaTest/it_can_calculate_south_africa_holidays.snap @@ -0,0 +1,58 @@ +[ + { + "name": "New Year's Day", + "date": "2022-01-01" + }, + { + "name": "Human Rights Day", + "date": "2022-03-21" + }, + { + "name": "Good Friday", + "date": "2022-04-15" + }, + { + "name": "Family Day", + "date": "2022-04-18" + }, + { + "name": "Freedom Day", + "date": "2022-04-27" + }, + { + "name": "Workers' Day", + "date": "2022-05-01" + }, + { + "name": "Workers' Day Observed", + "date": "2022-05-02" + }, + { + "name": "Youth Day", + "date": "2022-06-16" + }, + { + "name": "National Women's Day", + "date": "2022-08-09" + }, + { + "name": "Heritage Day", + "date": "2022-09-24" + }, + { + "name": "Day of Reconciliation", + "date": "2022-12-16" + }, + { + "name": "Christmas Day", + "date": "2022-12-25" + }, + { + "name": "Day of Goodwill", + "date": "2022-12-26" + }, + { + "name": "Christmas Day Observed", + "date": "2022-12-26" + } +] \ No newline at end of file diff --git a/tests/Countries/SouthAfricaTest.php b/tests/Countries/SouthAfricaTest.php new file mode 100644 index 00000000..dbe9ba0c --- /dev/null +++ b/tests/Countries/SouthAfricaTest.php @@ -0,0 +1,18 @@ +get(); + + expect($holidays) + ->toBeArray() + ->not()->toBeEmpty(); + + expect(formatDates($holidays))->toMatchSnapshot(); +});