From 5bb134957eb5c2349bbf57a714772e3718b114de Mon Sep 17 00:00:00 2001 From: Yazid KHALDI Date: Thu, 18 Jan 2024 01:17:20 +0100 Subject: [PATCH 1/6] add-Moroccan-holidays --- src/Countries/Morocco.php | 49 ++++++++++++++ .../it_can_calculate_morocco_holidays.snap | 66 +++++++++++++++++++ tests/Countries/MoroccoTest.php | 18 +++++ 3 files changed, 133 insertions(+) create mode 100644 src/Countries/Morocco.php create mode 100644 tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays.snap create mode 100644 tests/Countries/MoroccoTest.php diff --git a/src/Countries/Morocco.php b/src/Countries/Morocco.php new file mode 100644 index 000000000..12f0ba7bb --- /dev/null +++ b/src/Countries/Morocco.php @@ -0,0 +1,49 @@ + */ + protected function allHolidays(int $year): array + { + return array_merge([ + 'New Year\'s Day' => '01-01', + 'Proclamation of Independence Day' => '01-11', + 'Amazigh New Year (ⵉⴹ ⵏ ⵢⵉⵏⵏⴰⵢⵔ)' => '01-14', + 'Labour Day' => '05-01', + 'Throne Day' => '07-30', + 'Oued Ed-Dahab Day' => '08-14', + 'Revolution Day' => '08-20', + 'Youth Day' => '08-21', + 'Independence Day' => '11-18', + ], $this->variableHolidays($year)); + } + + /** @return array */ + protected function variableHolidays(int $year): array + { + /** + * The following holidays are considered public holidays in Morocco. However, their dates vary each year, + * as they are based on the Islamic Hijri (lunar) calendar. These holidays do not have a fixed date and + * occur based on the lunar calendar sequence. The order listed reflects the chronological occurrence + * of these holidays throughout the year. + */ + return [ + 'Eid al-Fitr' => '04-10', + 'Eid al-Fitr 2' => '04-11', + 'Eid al-Adha' => '06-17', + 'Eid al-Adha 2' => '06-18', + 'Islamic New Year' => '07-08', + 'Birthday of the Prophet Muhammad' => '09-16', + 'Birthday of the Prophet Muhammad 2' => '09-17' + ]; + } +} diff --git a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays.snap b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays.snap new file mode 100644 index 000000000..ae99be4d6 --- /dev/null +++ b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays.snap @@ -0,0 +1,66 @@ +[ + { + "name": "New Year's Day", + "date": "2024-01-01" + }, + { + "name": "Proclamation of Independence Day", + "date": "2024-01-11" + }, + { + "name": "Amazigh New Year (\u2d49\u2d39 \u2d4f \u2d62\u2d49\u2d4f\u2d4f\u2d30\u2d62\u2d54)", + "date": "2024-01-14" + }, + { + "name": "Eid al-Fitr", + "date": "2024-04-10" + }, + { + "name": "Eid al-Fitr 2", + "date": "2024-04-11" + }, + { + "name": "Labour Day", + "date": "2024-05-01" + }, + { + "name": "Eid al-Adha", + "date": "2024-06-17" + }, + { + "name": "Eid al-Adha 2", + "date": "2024-06-18" + }, + { + "name": "Islamic New Year", + "date": "2024-07-08" + }, + { + "name": "Throne Day", + "date": "2024-07-30" + }, + { + "name": "Oued Ed-Dahab Day", + "date": "2024-08-14" + }, + { + "name": "Revolution Day", + "date": "2024-08-20" + }, + { + "name": "Youth Day", + "date": "2024-08-21" + }, + { + "name": "Birthday of the Prophet Muhammad", + "date": "2024-09-16" + }, + { + "name": "Birthday of the Prophet Muhammad 2", + "date": "2024-09-17" + }, + { + "name": "Independence Day", + "date": "2024-11-18" + } +] \ No newline at end of file diff --git a/tests/Countries/MoroccoTest.php b/tests/Countries/MoroccoTest.php new file mode 100644 index 000000000..ab717c5e1 --- /dev/null +++ b/tests/Countries/MoroccoTest.php @@ -0,0 +1,18 @@ +get(); + + expect($holidays) + ->toBeArray() + ->not()->toBeEmpty(); + + expect(formatDates($holidays))->toMatchSnapshot(); +}); From 3f81a1c8d2b1dc1332e659abc94a09d9bf6de5b1 Mon Sep 17 00:00:00 2001 From: Yazid KHALDI Date: Sat, 20 Jan 2024 04:23:26 +0100 Subject: [PATCH 2/6] integrate hijri-dates to calculate Islamic Holidays --- src/Countries/Morocco.php | 46 ++++++++++--- ...t_can_calculate_morocco_holidays_2023.snap | 66 +++++++++++++++++++ ..._can_calculate_morocco_holidays_2024.snap} | 0 ...t_can_calculate_morocco_holidays_2025.snap | 66 +++++++++++++++++++ ...t_can_calculate_morocco_holidays_2026.snap | 66 +++++++++++++++++++ tests/Countries/MoroccoTest.php | 38 ++++++++++- 6 files changed, 273 insertions(+), 9 deletions(-) create mode 100644 tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2023.snap rename tests/.pest/snapshots/Countries/MoroccoTest/{it_can_calculate_morocco_holidays.snap => it_can_calculate_morocco_holidays_2024.snap} (100%) create mode 100644 tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2025.snap create mode 100644 tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2026.snap diff --git a/src/Countries/Morocco.php b/src/Countries/Morocco.php index 12f0ba7bb..3b562c2ec 100644 --- a/src/Countries/Morocco.php +++ b/src/Countries/Morocco.php @@ -3,6 +3,7 @@ namespace Spatie\Holidays\Countries; use Carbon\CarbonImmutable; +use GeniusTS\HijriDate\Hijri; class Morocco extends Country { @@ -36,14 +37,43 @@ protected function variableHolidays(int $year): array * occur based on the lunar calendar sequence. The order listed reflects the chronological occurrence * of these holidays throughout the year. */ - return [ - 'Eid al-Fitr' => '04-10', - 'Eid al-Fitr 2' => '04-11', - 'Eid al-Adha' => '06-17', - 'Eid al-Adha 2' => '06-18', - 'Islamic New Year' => '07-08', - 'Birthday of the Prophet Muhammad' => '09-16', - 'Birthday of the Prophet Muhammad 2' => '09-17' + + // Set default adjustment for Hijri conversion + Hijri::setDefaultAdjustment(-1); + + // Get the current Hijri year + $currentHijriYear = (int) Hijri::convertToHijri($year . "-01-01")->format('Y'); + + // Define Islamic holidays on the Hijri calendar + $islamicHolidaysOnHijri = [ + 'Islamic New Year' => '01-01', + 'Birthday of the Prophet Muhammad' => '03-12', + 'Birthday of the Prophet Muhammad 2' => '03-13', + 'Eid al-Fitr' => '10-01', + 'Eid al-Fitr 2' => '10-02', + 'Eid al-Adha' => '12-10', + 'Eid al-Adha 2' => '12-11', ]; + + $islamicHolidaysOnGregorian = []; + + // Convert Hijri dates to Gregorian and filter based on the input year + foreach ($islamicHolidaysOnHijri as $holidayTitle => $hijriHolidayDate) { + list($hijriHolidayMonth, $hijriHolidayDay) = explode('-', $hijriHolidayDate); + + // Convert to Gregorian for the current and next Hijri year + $currentGregorianDate = Hijri::convertToGregorian($hijriHolidayDay, $hijriHolidayMonth, $currentHijriYear); + $nextHijriYear = $currentHijriYear + 1; + $nextGregorianDate = Hijri::convertToGregorian($hijriHolidayDay, $hijriHolidayMonth, $nextHijriYear); + + // Check if the holiday falls in the input year + if ($currentGregorianDate->format('Y') == $year) { + $islamicHolidaysOnGregorian[$holidayTitle] = $currentGregorianDate->format('m-d'); + } elseif ($nextGregorianDate->format('Y') == $year) { + $islamicHolidaysOnGregorian[$holidayTitle] = $nextGregorianDate->format('m-d'); + } + } + + return $islamicHolidaysOnGregorian; } } diff --git a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2023.snap b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2023.snap new file mode 100644 index 000000000..49dcf7dac --- /dev/null +++ b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2023.snap @@ -0,0 +1,66 @@ +[ + { + "name": "New Year's Day", + "date": "2023-01-01" + }, + { + "name": "Proclamation of Independence Day", + "date": "2023-01-11" + }, + { + "name": "Amazigh New Year (\u2d49\u2d39 \u2d4f \u2d62\u2d49\u2d4f\u2d4f\u2d30\u2d62\u2d54)", + "date": "2023-01-14" + }, + { + "name": "Eid al-Fitr", + "date": "2023-04-22" + }, + { + "name": "Eid al-Fitr 2", + "date": "2023-04-23" + }, + { + "name": "Labour Day", + "date": "2023-05-01" + }, + { + "name": "Eid al-Adha", + "date": "2023-06-29" + }, + { + "name": "Eid al-Adha 2", + "date": "2023-06-30" + }, + { + "name": "Islamic New Year", + "date": "2023-07-19" + }, + { + "name": "Throne Day", + "date": "2023-07-30" + }, + { + "name": "Oued Ed-Dahab Day", + "date": "2023-08-14" + }, + { + "name": "Revolution Day", + "date": "2023-08-20" + }, + { + "name": "Youth Day", + "date": "2023-08-21" + }, + { + "name": "Birthday of the Prophet Muhammad", + "date": "2023-09-27" + }, + { + "name": "Birthday of the Prophet Muhammad 2", + "date": "2023-09-28" + }, + { + "name": "Independence Day", + "date": "2023-11-18" + } +] \ No newline at end of file diff --git a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays.snap b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2024.snap similarity index 100% rename from tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays.snap rename to tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2024.snap diff --git a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2025.snap b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2025.snap new file mode 100644 index 000000000..996f0f546 --- /dev/null +++ b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2025.snap @@ -0,0 +1,66 @@ +[ + { + "name": "New Year's Day", + "date": "2025-01-01" + }, + { + "name": "Proclamation of Independence Day", + "date": "2025-01-11" + }, + { + "name": "Amazigh New Year (\u2d49\u2d39 \u2d4f \u2d62\u2d49\u2d4f\u2d4f\u2d30\u2d62\u2d54)", + "date": "2025-01-14" + }, + { + "name": "Eid al-Fitr", + "date": "2025-03-31" + }, + { + "name": "Eid al-Fitr 2", + "date": "2025-04-01" + }, + { + "name": "Labour Day", + "date": "2025-05-01" + }, + { + "name": "Eid al-Adha", + "date": "2025-06-07" + }, + { + "name": "Eid al-Adha 2", + "date": "2025-06-08" + }, + { + "name": "Islamic New Year", + "date": "2025-06-27" + }, + { + "name": "Throne Day", + "date": "2025-07-30" + }, + { + "name": "Oued Ed-Dahab Day", + "date": "2025-08-14" + }, + { + "name": "Revolution Day", + "date": "2025-08-20" + }, + { + "name": "Youth Day", + "date": "2025-08-21" + }, + { + "name": "Birthday of the Prophet Muhammad", + "date": "2025-09-05" + }, + { + "name": "Birthday of the Prophet Muhammad 2", + "date": "2025-09-06" + }, + { + "name": "Independence Day", + "date": "2025-11-18" + } +] \ No newline at end of file diff --git a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2026.snap b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2026.snap new file mode 100644 index 000000000..f980a64e2 --- /dev/null +++ b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2026.snap @@ -0,0 +1,66 @@ +[ + { + "name": "New Year's Day", + "date": "2026-01-01" + }, + { + "name": "Proclamation of Independence Day", + "date": "2026-01-11" + }, + { + "name": "Amazigh New Year (\u2d49\u2d39 \u2d4f \u2d62\u2d49\u2d4f\u2d4f\u2d30\u2d62\u2d54)", + "date": "2026-01-14" + }, + { + "name": "Eid al-Fitr", + "date": "2026-03-20" + }, + { + "name": "Eid al-Fitr 2", + "date": "2026-03-21" + }, + { + "name": "Labour Day", + "date": "2026-05-01" + }, + { + "name": "Eid al-Adha", + "date": "2026-05-27" + }, + { + "name": "Eid al-Adha 2", + "date": "2026-05-28" + }, + { + "name": "Islamic New Year", + "date": "2026-06-17" + }, + { + "name": "Throne Day", + "date": "2026-07-30" + }, + { + "name": "Oued Ed-Dahab Day", + "date": "2026-08-14" + }, + { + "name": "Revolution Day", + "date": "2026-08-20" + }, + { + "name": "Youth Day", + "date": "2026-08-21" + }, + { + "name": "Birthday of the Prophet Muhammad", + "date": "2026-08-26" + }, + { + "name": "Birthday of the Prophet Muhammad 2", + "date": "2026-08-27" + }, + { + "name": "Independence Day", + "date": "2026-11-18" + } +] \ No newline at end of file diff --git a/tests/Countries/MoroccoTest.php b/tests/Countries/MoroccoTest.php index ab717c5e1..9c0edfa5c 100644 --- a/tests/Countries/MoroccoTest.php +++ b/tests/Countries/MoroccoTest.php @@ -5,9 +5,33 @@ use Carbon\CarbonImmutable; use Spatie\Holidays\Holidays; -it('can calculate morocco holidays', function () { +it('can calculate morocco holidays 2024', function () { CarbonImmutable::setTestNowAndTimezone('2024-01-01'); + $holidays = Holidays::for(country: 'ma')->get(); + + expect($holidays) + ->toBeArray() + ->not()->toBeEmpty(); + + expect(formatDates($holidays))->toMatchSnapshot(); +}); + +it('can calculate morocco holidays 2023', function () { + CarbonImmutable::setTestNowAndTimezone('2023-01-01'); + + $holidays = Holidays::for(country: 'ma')->get(); + + expect($holidays) + ->toBeArray() + ->not()->toBeEmpty(); + + expect(formatDates($holidays))->toMatchSnapshot(); +}); + +it('can calculate morocco holidays 2025', function () { + CarbonImmutable::setTestNowAndTimezone('2025-01-01'); + $holidays = Holidays::for(country: 'ma')->get(); expect($holidays) @@ -16,3 +40,15 @@ expect(formatDates($holidays))->toMatchSnapshot(); }); + +it('can calculate morocco holidays 2026', function () { + CarbonImmutable::setTestNowAndTimezone('2026-01-01'); + + $holidays = Holidays::for(country: 'ma')->get(); + + expect($holidays) + ->toBeArray() + ->not()->toBeEmpty(); + + expect(formatDates($holidays))->toMatchSnapshot(); +}); \ No newline at end of file From 66015dfccc8b0b57a59df400c45a15c3a594c4e4 Mon Sep 17 00:00:00 2001 From: Yazid KHALDI Date: Sun, 21 Jan 2024 02:29:30 +0100 Subject: [PATCH 3/6] Fix PHPStan failures in GitHub Actions --- src/Countries/Morocco.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Countries/Morocco.php b/src/Countries/Morocco.php index 3b562c2ec..6d73cf56f 100644 --- a/src/Countries/Morocco.php +++ b/src/Countries/Morocco.php @@ -12,7 +12,6 @@ public function countryCode(): string return 'ma'; } - /** @return array */ protected function allHolidays(int $year): array { return array_merge([ @@ -62,15 +61,15 @@ protected function variableHolidays(int $year): array list($hijriHolidayMonth, $hijriHolidayDay) = explode('-', $hijriHolidayDate); // Convert to Gregorian for the current and next Hijri year - $currentGregorianDate = Hijri::convertToGregorian($hijriHolidayDay, $hijriHolidayMonth, $currentHijriYear); + $currentGregorianDate = Hijri::convertToGregorian((int)$hijriHolidayDay, (int)$hijriHolidayMonth, (int)$currentHijriYear); $nextHijriYear = $currentHijriYear + 1; - $nextGregorianDate = Hijri::convertToGregorian($hijriHolidayDay, $hijriHolidayMonth, $nextHijriYear); + $nextGregorianDate = Hijri::convertToGregorian((int)$hijriHolidayDay, (int)$hijriHolidayMonth, (int)$nextHijriYear); // Check if the holiday falls in the input year if ($currentGregorianDate->format('Y') == $year) { - $islamicHolidaysOnGregorian[$holidayTitle] = $currentGregorianDate->format('m-d'); + $islamicHolidaysOnGregorian[$holidayTitle] = $currentGregorianDate->toImmutable(); } elseif ($nextGregorianDate->format('Y') == $year) { - $islamicHolidaysOnGregorian[$holidayTitle] = $nextGregorianDate->format('m-d'); + $islamicHolidaysOnGregorian[$holidayTitle] = $nextGregorianDate->toImmutable(); } } From dc812c7434d21877bee377782867df69af5e8d1d Mon Sep 17 00:00:00 2001 From: Yazid KHALDI Date: Mon, 11 Mar 2024 01:59:39 +0000 Subject: [PATCH 4/6] Refactor: Removed dependency on geniusts/hijri-dates package and integrated the calculation function from the Ministry of Endowments and Islamic Affairs. --- src/Countries/Morocco.php | 94 +++++++++++++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 18 deletions(-) diff --git a/src/Countries/Morocco.php b/src/Countries/Morocco.php index 6d73cf56f..7eb584d98 100644 --- a/src/Countries/Morocco.php +++ b/src/Countries/Morocco.php @@ -3,7 +3,6 @@ namespace Spatie\Holidays\Countries; use Carbon\CarbonImmutable; -use GeniusTS\HijriDate\Hijri; class Morocco extends Country { @@ -30,6 +29,9 @@ protected function allHolidays(int $year): array /** @return array */ protected function variableHolidays(int $year): array { + // Calculate the current Hijri year based on the Gregorian year + $currentHijriYear = 1444 + ($year - 2022); + /** * The following holidays are considered public holidays in Morocco. However, their dates vary each year, * as they are based on the Islamic Hijri (lunar) calendar. These holidays do not have a fixed date and @@ -37,11 +39,6 @@ protected function variableHolidays(int $year): array * of these holidays throughout the year. */ - // Set default adjustment for Hijri conversion - Hijri::setDefaultAdjustment(-1); - - // Get the current Hijri year - $currentHijriYear = (int) Hijri::convertToHijri($year . "-01-01")->format('Y'); // Define Islamic holidays on the Hijri calendar $islamicHolidaysOnHijri = [ @@ -55,24 +52,85 @@ protected function variableHolidays(int $year): array ]; $islamicHolidaysOnGregorian = []; - // Convert Hijri dates to Gregorian and filter based on the input year foreach ($islamicHolidaysOnHijri as $holidayTitle => $hijriHolidayDate) { list($hijriHolidayMonth, $hijriHolidayDay) = explode('-', $hijriHolidayDate); - - // Convert to Gregorian for the current and next Hijri year - $currentGregorianDate = Hijri::convertToGregorian((int)$hijriHolidayDay, (int)$hijriHolidayMonth, (int)$currentHijriYear); - $nextHijriYear = $currentHijriYear + 1; - $nextGregorianDate = Hijri::convertToGregorian((int)$hijriHolidayDay, (int)$hijriHolidayMonth, (int)$nextHijriYear); - - // Check if the holiday falls in the input year - if ($currentGregorianDate->format('Y') == $year) { - $islamicHolidaysOnGregorian[$holidayTitle] = $currentGregorianDate->toImmutable(); - } elseif ($nextGregorianDate->format('Y') == $year) { - $islamicHolidaysOnGregorian[$holidayTitle] = $nextGregorianDate->toImmutable(); + $vlideYear = null; + $tempCurrentHijriYear = $currentHijriYear; + while ($vlideYear != $year) { + // Convert the current Hijri holiday to Gregorian + $GregorianDate = $this->islamicToGregorian($tempCurrentHijriYear--, $hijriHolidayMonth, $hijriHolidayDay); + $vlideYear = $GregorianDate['year']; } + // Store the Gregorian date of the Islamic holiday + $islamicHolidaysOnGregorian[$holidayTitle] = CarbonImmutable::createFromFormat('Y-m-d', sprintf('%s-%s-%s', $GregorianDate['year'], $GregorianDate['month'], $GregorianDate['day'])); } return $islamicHolidaysOnGregorian; } + + /** + * Converts a Hijri date to the corresponding Gregorian date. + * This function is adapted from the conversion tool used on the Moroccan + * Minister of Endowments and Islamic Affairs official website. + * https://www.habous.gov.ma/محول-التاريخ + * + * @param int $y The Hijri year. + * @param int $m The Hijri month. + * @param int $d The Hijri day. + * @return array An array containing the corresponding Gregorian date in the format ['year' => YYYY, 'month' => MM, 'day' => DD]. + */ + private function islamicToGregorian($y, $m, $d) + { + $delta = 0; + $jd = $this->intPart((11 * $y + 3) / 30) + 354 * $y + 30 * $m - $this->intPart(($m - 1) / 2) + $d + 1948440 - 385 + $delta; + if ($jd > 2299160) { + $l = $jd + 68569; + $n = $this->intPart((4 * $l) / 146097); + $l = $l - $this->intPart((146097 * $n + 3) / 4); + $i = $this->intPart((4000 * ($l + 1)) / 1461001); + $l = $l - $this->intPart((1461 * $i) / 4) + 31; + $j = $this->intPart((80 * $l) / 2447); + $d = $l - $this->intPart((2447 * $j) / 80); + $l = $this->intPart($j / 11); + $m = $j + 2 - 12 * $l; + $y = 100 * ($n - 49) + $i + $l; + } else { + $j = $jd + 1402; + $k = $this->intPart(($j - 1) / 1461); + $l = $j - 1461 * $k; + $n = $this->intPart(($l - 1) / 365) - $this->intPart($l / 1461); + $i = $l - 365 * $n + 30; + $j = $this->intPart((80 * $i) / 2447); + $d = $i - $this->intPart((2447 * $j) / 80); + $i = $this->intPart($j / 11); + $m = $j + 2 - 12 * $i; + $y = 4 * $k + $n + $i - 4716; + } + + return [ + "year" => $y, + "month" => $m, + "day" => $d + ]; + } + + /** + * Rounds a floating-point number to the nearest integer. + * If the floating-point number is negative, it uses ceil function. + * If the floating-point number is positive, it uses floor function. + * + * @param float $floatNum The floating-point number to be rounded. + * @return int The rounded integer value. + */ + private function intPart($floatNum) + { + // Check if the floating-point number is negative + if ($floatNum < -0.0000001) { + // If negative, round up using ceil + return ceil($floatNum - 0.0000001); + } + // If positive or zero, round down using floor + return floor($floatNum + 0.0000001); + } } From 7c41e213203b333c68b71a079da3e7811a7138bc Mon Sep 17 00:00:00 2001 From: Yazid KHALDI Date: Mon, 11 Mar 2024 02:36:19 +0000 Subject: [PATCH 5/6] Add translations for holiday names, include missing holiday, and fix unit test coverage for the new holiday addition --- lang/morocco/ar/holidays.json | 19 +++++++++++++++++++ src/Countries/Morocco.php | 16 +++++++++++++++- ...t_can_calculate_morocco_holidays_2023.snap | 4 ++++ ...t_can_calculate_morocco_holidays_2024.snap | 4 ++++ ...t_can_calculate_morocco_holidays_2025.snap | 4 ++++ ...t_can_calculate_morocco_holidays_2026.snap | 4 ++++ 6 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 lang/morocco/ar/holidays.json diff --git a/lang/morocco/ar/holidays.json b/lang/morocco/ar/holidays.json new file mode 100644 index 000000000..6a09257cf --- /dev/null +++ b/lang/morocco/ar/holidays.json @@ -0,0 +1,19 @@ +{ + "New Year\\'s Day": "رأس السنة الميلادية", + "Proclamation of Independence Day": "تقديم وثيقة الاستقلال", + "Amazigh New Year (ⵉⴹ ⵏ ⵢⵉⵏⵏⴰⵢⵔ)": "رأس السنة الأمازيغية", + "Labour Day": "عيد الشغل", + "Throne Day": "عيد العرش", + "Oued Ed-Dahab Day": "استرجاع إقليم وادي الذهب", + "Revolution Day": "ثورة الملك والشعب", + "Youth Day": "عيد الشباب", + "Green March": "ذكرى المسيرة الخضراء", + "Independence Day": "عيد الاستقلال", + "Islamic New Year": "رأس السنة الهجرية", + "Birthday of the Prophet Muhammad": "عيد المولد النبوي", + "Birthday of the Prophet Muhammad 2": "تاني ايام عيد المولد النبوي", + "Eid al-Fitr": "عيد الفطر", + "Eid al-Fitr 2": "تاني ايام عيد الفطر", + "Eid al-Adha": "عيد الأضحى", + "Eid al-Adha 2": "تاني ايام عيد الأضحى" +} \ No newline at end of file diff --git a/src/Countries/Morocco.php b/src/Countries/Morocco.php index 7eb584d98..5d07dc12d 100644 --- a/src/Countries/Morocco.php +++ b/src/Countries/Morocco.php @@ -3,14 +3,24 @@ namespace Spatie\Holidays\Countries; use Carbon\CarbonImmutable; +use Spatie\Holidays\Contracts\HasTranslations; +use Spatie\Holidays\Concerns\Translatable; +use Spatie\Holidays\Exceptions\InvalidYear; -class Morocco extends Country +class Morocco extends Country implements HasTranslations { + use Translatable; + public function countryCode(): string { return 'ma'; } + public function defaultLocale(): string + { + return 'en'; + } + protected function allHolidays(int $year): array { return array_merge([ @@ -22,6 +32,7 @@ protected function allHolidays(int $year): array 'Oued Ed-Dahab Day' => '08-14', 'Revolution Day' => '08-20', 'Youth Day' => '08-21', + 'Green March' => '11-06', 'Independence Day' => '11-18', ], $this->variableHolidays($year)); } @@ -61,6 +72,9 @@ protected function variableHolidays(int $year): array // Convert the current Hijri holiday to Gregorian $GregorianDate = $this->islamicToGregorian($tempCurrentHijriYear--, $hijriHolidayMonth, $hijriHolidayDay); $vlideYear = $GregorianDate['year']; + if ($vlideYear < 1976) { + throw InvalidYear::yearTooLow(1976); + } } // Store the Gregorian date of the Islamic holiday $islamicHolidaysOnGregorian[$holidayTitle] = CarbonImmutable::createFromFormat('Y-m-d', sprintf('%s-%s-%s', $GregorianDate['year'], $GregorianDate['month'], $GregorianDate['day'])); diff --git a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2023.snap b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2023.snap index 49dcf7dac..cd561ee93 100644 --- a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2023.snap +++ b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2023.snap @@ -59,6 +59,10 @@ "name": "Birthday of the Prophet Muhammad 2", "date": "2023-09-28" }, + { + "name": "Green March", + "date": "2023-11-06" + }, { "name": "Independence Day", "date": "2023-11-18" diff --git a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2024.snap b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2024.snap index ae99be4d6..8f3c17ee1 100644 --- a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2024.snap +++ b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2024.snap @@ -59,6 +59,10 @@ "name": "Birthday of the Prophet Muhammad 2", "date": "2024-09-17" }, + { + "name": "Green March", + "date": "2024-11-06" + }, { "name": "Independence Day", "date": "2024-11-18" diff --git a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2025.snap b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2025.snap index 996f0f546..c0f36341f 100644 --- a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2025.snap +++ b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2025.snap @@ -59,6 +59,10 @@ "name": "Birthday of the Prophet Muhammad 2", "date": "2025-09-06" }, + { + "name": "Green March", + "date": "2025-11-06" + }, { "name": "Independence Day", "date": "2025-11-18" diff --git a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2026.snap b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2026.snap index f980a64e2..648855f93 100644 --- a/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2026.snap +++ b/tests/.pest/snapshots/Countries/MoroccoTest/it_can_calculate_morocco_holidays_2026.snap @@ -59,6 +59,10 @@ "name": "Birthday of the Prophet Muhammad 2", "date": "2026-08-27" }, + { + "name": "Green March", + "date": "2026-11-06" + }, { "name": "Independence Day", "date": "2026-11-18" From b1ed9f9dcab21ef8e66c6caf94c00c8173f1428a Mon Sep 17 00:00:00 2001 From: Yazid KHALDI Date: Mon, 11 Mar 2024 03:29:40 +0000 Subject: [PATCH 6/6] Fix PHPStan issues & Code Style --- src/Countries/Morocco.php | 37 ++++++++++++++++++--------------- tests/Countries/MoroccoTest.php | 4 ++-- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/Countries/Morocco.php b/src/Countries/Morocco.php index 5d07dc12d..2d0ed9df2 100644 --- a/src/Countries/Morocco.php +++ b/src/Countries/Morocco.php @@ -3,8 +3,8 @@ namespace Spatie\Holidays\Countries; use Carbon\CarbonImmutable; -use Spatie\Holidays\Contracts\HasTranslations; use Spatie\Holidays\Concerns\Translatable; +use Spatie\Holidays\Contracts\HasTranslations; use Spatie\Holidays\Exceptions\InvalidYear; class Morocco extends Country implements HasTranslations @@ -50,7 +50,6 @@ protected function variableHolidays(int $year): array * of these holidays throughout the year. */ - // Define Islamic holidays on the Hijri calendar $islamicHolidaysOnHijri = [ 'Islamic New Year' => '01-01', @@ -65,19 +64,22 @@ protected function variableHolidays(int $year): array $islamicHolidaysOnGregorian = []; // Convert Hijri dates to Gregorian and filter based on the input year foreach ($islamicHolidaysOnHijri as $holidayTitle => $hijriHolidayDate) { - list($hijriHolidayMonth, $hijriHolidayDay) = explode('-', $hijriHolidayDate); + [$hijriHolidayMonth, $hijriHolidayDay] = explode('-', $hijriHolidayDate); $vlideYear = null; + + $GregorianDate = $this->islamicToGregorian($currentHijriYear, (int) $hijriHolidayMonth, (int) $hijriHolidayDay); + $vlideYear = $GregorianDate['year']; $tempCurrentHijriYear = $currentHijriYear; while ($vlideYear != $year) { // Convert the current Hijri holiday to Gregorian - $GregorianDate = $this->islamicToGregorian($tempCurrentHijriYear--, $hijriHolidayMonth, $hijriHolidayDay); + $GregorianDate = $this->islamicToGregorian($tempCurrentHijriYear--, (int) $hijriHolidayMonth, (int) $hijriHolidayDay); $vlideYear = $GregorianDate['year']; if ($vlideYear < 1976) { throw InvalidYear::yearTooLow(1976); } } // Store the Gregorian date of the Islamic holiday - $islamicHolidaysOnGregorian[$holidayTitle] = CarbonImmutable::createFromFormat('Y-m-d', sprintf('%s-%s-%s', $GregorianDate['year'], $GregorianDate['month'], $GregorianDate['day'])); + $islamicHolidaysOnGregorian[$holidayTitle] = CarbonImmutable::createFromFormat('Y-m-d', sprintf('%s-%s-%s', $GregorianDate['year'], $GregorianDate['month'], $GregorianDate['day'])); } return $islamicHolidaysOnGregorian; @@ -88,13 +90,13 @@ protected function variableHolidays(int $year): array * This function is adapted from the conversion tool used on the Moroccan * Minister of Endowments and Islamic Affairs official website. * https://www.habous.gov.ma/محول-التاريخ - * - * @param int $y The Hijri year. - * @param int $m The Hijri month. - * @param int $d The Hijri day. - * @return array An array containing the corresponding Gregorian date in the format ['year' => YYYY, 'month' => MM, 'day' => DD]. + * + * @param int $y The Hijri year. + * @param int $m The Hijri month. + * @param int $d The Hijri day. + * @return array{year: int, month: int, day: int} An array containing the corresponding Gregorian date in the format ['year' => YYYY, 'month' => MM, 'day' => DD]. */ - private function islamicToGregorian($y, $m, $d) + private function islamicToGregorian(int $y, int $m, int $d): array { $delta = 0; $jd = $this->intPart((11 * $y + 3) / 30) + 354 * $y + 30 * $m - $this->intPart(($m - 1) / 2) + $d + 1948440 - 385 + $delta; @@ -123,9 +125,9 @@ private function islamicToGregorian($y, $m, $d) } return [ - "year" => $y, - "month" => $m, - "day" => $d + 'year' => (int) $y, + 'month' => (int) $m, + 'day' => (int) $d, ]; } @@ -133,9 +135,9 @@ private function islamicToGregorian($y, $m, $d) * Rounds a floating-point number to the nearest integer. * If the floating-point number is negative, it uses ceil function. * If the floating-point number is positive, it uses floor function. - * - * @param float $floatNum The floating-point number to be rounded. - * @return int The rounded integer value. + * + * @param float $floatNum The floating-point number to be rounded. + * @return float The rounded integer value. */ private function intPart($floatNum) { @@ -144,6 +146,7 @@ private function intPart($floatNum) // If negative, round up using ceil return ceil($floatNum - 0.0000001); } + // If positive or zero, round down using floor return floor($floatNum + 0.0000001); } diff --git a/tests/Countries/MoroccoTest.php b/tests/Countries/MoroccoTest.php index 9c0edfa5c..d3b251ec7 100644 --- a/tests/Countries/MoroccoTest.php +++ b/tests/Countries/MoroccoTest.php @@ -9,7 +9,7 @@ CarbonImmutable::setTestNowAndTimezone('2024-01-01'); $holidays = Holidays::for(country: 'ma')->get(); - + expect($holidays) ->toBeArray() ->not()->toBeEmpty(); @@ -51,4 +51,4 @@ ->not()->toBeEmpty(); expect(formatDates($holidays))->toMatchSnapshot(); -}); \ No newline at end of file +});