From c4b5854138f30d64a6231dbe719460a93c6115fb Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sun, 21 Jan 2024 16:01:07 +0200 Subject: [PATCH 01/20] Add Egyptian holidays --- composer.json | 5 +- src/Countries/Egypt.php | 172 ++++++++++++++++++ .../it_can_calculate_egypt_holidays_2024.snap | 126 +++++++++++++ tests/Countries/EgyptTest.php | 18 ++ 4 files changed, 319 insertions(+), 2 deletions(-) create mode 100644 src/Countries/Egypt.php create mode 100644 tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays_2024.snap create mode 100644 tests/Countries/EgyptTest.php diff --git a/composer.json b/composer.json index 9f8a2f7fb..a2b375768 100644 --- a/composer.json +++ b/composer.json @@ -21,8 +21,9 @@ ], "require": { "php": "^8.1", - "nesbot/carbon": "^2.72.1", - "ext-calendar": "*" + "ext-calendar": "*", + "geniusts/hijri-dates": "^1.1", + "nesbot/carbon": "^2.72.1" }, "require-dev": { "laravel/pint": "^1.0", diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php new file mode 100644 index 000000000..d700c2e34 --- /dev/null +++ b/src/Countries/Egypt.php @@ -0,0 +1,172 @@ + + */ + protected function allHolidays(int $year): array + { + $fixedHolidays = $this->getFixedHolidays($year); + $variableHolidays = $this->variableHolidays($year); + + return array_merge($fixedHolidays, $variableHolidays); + } + + /** + * @param int $year + * @return array + */ + private function getFixedHolidays(int $year): array + { + $holidays = [ + 'Coptic Christmas Day' => CarbonImmutable::create($year, 1, 7), + 'Revolution Day 2011' => CarbonImmutable::create($year, 1, 25), + 'Sinai Liberation Day' => CarbonImmutable::create($year, 4, 25), + 'Labour Day' => CarbonImmutable::create($year, 5, 1), + 'June 30 Revolution' => CarbonImmutable::create($year, 6, 30), + 'Revolution Day' => CarbonImmutable::create($year, 7, 23), + 'Armed Forces Day' => CarbonImmutable::create($year, 10, 6), + 'Spring Festival' => $this->orthodoxEaster($year)->addDay()->toImmutable() + ]; + + foreach ($holidays as $name => $date) { + $holidays = array_merge($holidays, $this->adjustForWeekend($name, $date)); + } + + return $holidays; + } + + /** + * @param int $year + * @return array + */ + protected function variableHolidays(int $year): array + { + $orthodoxEaster = $this->orthodoxEaster($year); + + $copticHolidays = [ + 'Coptic Good Friday' => $orthodoxEaster->subDays(2)->toImmutable(), + 'Coptic Holy Saturday' => $orthodoxEaster->subDays()->toImmutable(), + 'Coptic Easter Sunday' => $orthodoxEaster->toImmutable(), + 'Nayrouz' => CarbonImmutable::create($year, 9, 11), + ]; + + $otherHolidays = [ + 'Flooding of the Nile' => CarbonImmutable::create($year, 8, 15), + 'December Solstice' => CarbonImmutable::create($year, 12, 21), + 'March Equinox' => CarbonImmutable::create($year, 3, 20), + 'September Equinox' => CarbonImmutable::create($year, 9, 22), + 'June Solstice' => CarbonImmutable::create($year, 6, 21), + ]; + + $hijriHolidays = [ + 'Islamic New Year' => '01-01', + 'Ashura' => '01-10', + 'Birthday of the Prophet Muhammad' => '03-12', + 'Eid al-Fitr' => '10-01', + 'Eid al-Fitr Day 2' => '10-02', + 'Eid al-Fitr Day 3' => '10-03', + 'Arafat Day' => '12-09', + 'Eid al-Adha' => '12-10', + 'Eid al-Adha Day 2' => '12-11', + 'Eid al-Adha Day 3' => '12-12', + 'Eid al-Adha Day 4' => '12-13', + ]; + + return array_merge($copticHolidays, $otherHolidays, $this->convertHijriToGregorianHolidays($hijriHolidays, $year)); + } + + /** + * @param array $hijriHolidays + * @param int $year + * @return array + */ + private function convertHijriToGregorianHolidays(array $hijriHolidays, int $year): array + { + /** + * --------------------------------------------------------------- + * Code Adaptation + * --------------------------------------------------------------- + * This strategy was adapted from PR #56. + * Original contribution by: YazidKHALDI + * See: https://github.com/spatie/holidays/pull/56/ + * --------------------------------------------------------------- + */ + + Hijri::setDefaultAdjustment(-1); + + $currentHijriYear = (int)Hijri::convertToHijri($year . "-01-01")->format('Y'); + $gregorianHolidays = []; + + foreach ($hijriHolidays as $holidayName => $hijriDate) { + $gregorianDate = $this->getGregorianDateForHijriHoliday($hijriDate, $currentHijriYear, $year); + if (!is_null($gregorianDate)) { + $gregorianHolidays[$holidayName] = $gregorianDate; + } + } + + return $gregorianHolidays; + } + + /** + * @param string $hijriDate + * @param int $hijriYear + * @param int $gregorianYear + * @return CarbonImmutable|null + */ + private function getGregorianDateForHijriHoliday(string $hijriDate, int $hijriYear, int $gregorianYear): ?CarbonImmutable + { + list($month, $day) = explode('-', $hijriDate); + $currentYearDate = Hijri::convertToGregorian((int)$day, (int)$month, $hijriYear); + + if ($currentYearDate->format('Y') == $gregorianYear) { + return $currentYearDate->toImmutable(); + } + + $nextYearDate = Hijri::convertToGregorian((int)$day, (int)$month, $hijriYear + 1); + if ($nextYearDate->format('Y') == $gregorianYear) { + return $nextYearDate->toImmutable(); + } + + return null; + } + + /** + * @param string $name + * @param CarbonImmutable|false $date + * @return array + */ + private function adjustForWeekend(string $name, CarbonImmutable|false $date): array + { + $adjustedHolidays = []; + + // Explicitly define this logic to avoid timezone confusion on the CarbonInterface::next() method + if ($date) { + if ($date->isFriday() || $date->isSaturday()) { + // If the holiday falls on a weekend (Friday or Saturday), it is observed on the following Sunday + $adjustedHolidays['Day off for ' . $name] = $date->next(CarbonInterface::SUNDAY); + } elseif ($date->isSunday() || $date->isThursday()) { + // If the holiday falls on a Sunday, it is observed on the same day + $adjustedHolidays[$name] = $date; + } else { + // If the holiday falls on a weekday (Monday, Tuesday, Wednesday), it is observed on the following Thursday + $adjustedHolidays['Day off for ' . $name] = $date->next(CarbonInterface::THURSDAY); + } + } + + return $adjustedHolidays; + } +} diff --git a/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays_2024.snap b/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays_2024.snap new file mode 100644 index 000000000..8afa6ed3b --- /dev/null +++ b/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays_2024.snap @@ -0,0 +1,126 @@ +[ + { + "name": "Coptic Christmas Day", + "date": "2024-01-07" + }, + { + "name": "Revolution Day 2011", + "date": "2024-01-25" + }, + { + "name": "March Equinox", + "date": "2024-03-20" + }, + { + "name": "Eid al-Fitr", + "date": "2024-04-10" + }, + { + "name": "Eid al-Fitr Day 2", + "date": "2024-04-11" + }, + { + "name": "Eid al-Fitr Day 3", + "date": "2024-04-12" + }, + { + "name": "Sinai Liberation Day", + "date": "2024-04-25" + }, + { + "name": "Labour Day", + "date": "2024-05-01" + }, + { + "name": "Day off for Labour Day", + "date": "2024-05-02" + }, + { + "name": "Coptic Good Friday", + "date": "2024-05-03" + }, + { + "name": "Coptic Holy Saturday", + "date": "2024-05-04" + }, + { + "name": "Coptic Easter Sunday", + "date": "2024-05-05" + }, + { + "name": "Spring Festival", + "date": "2024-05-06" + }, + { + "name": "Day off for Spring Festival", + "date": "2024-05-09" + }, + { + "name": "Arafat Day", + "date": "2024-06-16" + }, + { + "name": "Eid al-Adha", + "date": "2024-06-17" + }, + { + "name": "Eid al-Adha Day 2", + "date": "2024-06-18" + }, + { + "name": "Eid al-Adha Day 3", + "date": "2024-06-19" + }, + { + "name": "Eid al-Adha Day 4", + "date": "2024-06-20" + }, + { + "name": "June Solstice", + "date": "2024-06-21" + }, + { + "name": "June 30 Revolution", + "date": "2024-06-30" + }, + { + "name": "Islamic New Year", + "date": "2024-07-08" + }, + { + "name": "Ashura", + "date": "2024-07-17" + }, + { + "name": "Revolution Day", + "date": "2024-07-23" + }, + { + "name": "Day off for Revolution Day", + "date": "2024-07-25" + }, + { + "name": "Flooding of the Nile", + "date": "2024-08-15" + }, + { + "name": "Nayrouz", + "date": "2024-09-11" + }, + { + "name": "Birthday of the Prophet Muhammad", + "date": "2024-09-16" + }, + { + "name": "September Equinox", + "date": "2024-09-22" + }, + { + "name": "Armed Forces Day", + "date": "2024-10-06" + }, + { + "name": "December Solstice", + "date": "2024-12-21" + } +] \ No newline at end of file diff --git a/tests/Countries/EgyptTest.php b/tests/Countries/EgyptTest.php new file mode 100644 index 000000000..3dcecf4b8 --- /dev/null +++ b/tests/Countries/EgyptTest.php @@ -0,0 +1,18 @@ +get(); + + expect($holidays) + ->toBeArray() + ->not()->toBeEmpty(); + + expect(formatDates($holidays))->toMatchSnapshot(); +}); From 1e867de0dcab7e56d92476b86e1af4b42f2ecd68 Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sun, 21 Jan 2024 16:25:23 +0200 Subject: [PATCH 02/20] For consistency --- tests/Countries/EgyptTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Countries/EgyptTest.php b/tests/Countries/EgyptTest.php index 3dcecf4b8..dff7bbf8a 100644 --- a/tests/Countries/EgyptTest.php +++ b/tests/Countries/EgyptTest.php @@ -5,7 +5,7 @@ use Carbon\CarbonImmutable; use Spatie\Holidays\Holidays; -it('can calculate egypt holidays 2024', function () { +it('can calculate egypt holidays', function () { CarbonImmutable::setTestNowAndTimezone('2024-01-01', 'Africa/Cairo'); $holidays = Holidays::for(country: 'eg')->get(); From be6c4459b8aa3faedb8887b1833db1189bcd35d3 Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sun, 21 Jan 2024 18:23:35 +0200 Subject: [PATCH 03/20] Minor enhancements --- src/Countries/Egypt.php | 61 +++++++++---------- ...p => it_can_calculate_egypt_holidays.snap} | 0 2 files changed, 29 insertions(+), 32 deletions(-) rename tests/.pest/snapshots/Countries/EgyptTest/{it_can_calculate_egypt_holidays_2024.snap => it_can_calculate_egypt_holidays.snap} (100%) diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php index d700c2e34..468b33445 100644 --- a/src/Countries/Egypt.php +++ b/src/Countries/Egypt.php @@ -25,30 +25,6 @@ protected function allHolidays(int $year): array return array_merge($fixedHolidays, $variableHolidays); } - /** - * @param int $year - * @return array - */ - private function getFixedHolidays(int $year): array - { - $holidays = [ - 'Coptic Christmas Day' => CarbonImmutable::create($year, 1, 7), - 'Revolution Day 2011' => CarbonImmutable::create($year, 1, 25), - 'Sinai Liberation Day' => CarbonImmutable::create($year, 4, 25), - 'Labour Day' => CarbonImmutable::create($year, 5, 1), - 'June 30 Revolution' => CarbonImmutable::create($year, 6, 30), - 'Revolution Day' => CarbonImmutable::create($year, 7, 23), - 'Armed Forces Day' => CarbonImmutable::create($year, 10, 6), - 'Spring Festival' => $this->orthodoxEaster($year)->addDay()->toImmutable() - ]; - - foreach ($holidays as $name => $date) { - $holidays = array_merge($holidays, $this->adjustForWeekend($name, $date)); - } - - return $holidays; - } - /** * @param int $year * @return array @@ -57,19 +33,16 @@ protected function variableHolidays(int $year): array { $orthodoxEaster = $this->orthodoxEaster($year); - $copticHolidays = [ + $otherHolidays = [ 'Coptic Good Friday' => $orthodoxEaster->subDays(2)->toImmutable(), 'Coptic Holy Saturday' => $orthodoxEaster->subDays()->toImmutable(), 'Coptic Easter Sunday' => $orthodoxEaster->toImmutable(), - 'Nayrouz' => CarbonImmutable::create($year, 9, 11), - ]; - - $otherHolidays = [ 'Flooding of the Nile' => CarbonImmutable::create($year, 8, 15), - 'December Solstice' => CarbonImmutable::create($year, 12, 21), 'March Equinox' => CarbonImmutable::create($year, 3, 20), - 'September Equinox' => CarbonImmutable::create($year, 9, 22), 'June Solstice' => CarbonImmutable::create($year, 6, 21), + 'September Equinox' => CarbonImmutable::create($year, 9, 22), + 'Nayrouz' => CarbonImmutable::create($year, 9, 11), + 'December Solstice' => CarbonImmutable::create($year, 12, 21), ]; $hijriHolidays = [ @@ -86,7 +59,31 @@ protected function variableHolidays(int $year): array 'Eid al-Adha Day 4' => '12-13', ]; - return array_merge($copticHolidays, $otherHolidays, $this->convertHijriToGregorianHolidays($hijriHolidays, $year)); + return array_merge($otherHolidays, $this->convertHijriToGregorianHolidays($hijriHolidays, $year)); + } + + /** + * @param int $year + * @return array + */ + private function getFixedHolidays(int $year): array + { + $holidays = [ + 'Coptic Christmas Day' => CarbonImmutable::create($year, 1, 7), + 'Revolution Day 2011' => CarbonImmutable::create($year, 1, 25), + 'Sinai Liberation Day' => CarbonImmutable::create($year, 4, 25), + 'Labour Day' => CarbonImmutable::create($year, 5, 1), + 'June 30 Revolution' => CarbonImmutable::create($year, 6, 30), + 'Revolution Day' => CarbonImmutable::create($year, 7, 23), + 'Armed Forces Day' => CarbonImmutable::create($year, 10, 6), + 'Spring Festival' => $this->orthodoxEaster($year)->addDay()->toImmutable() + ]; + + foreach ($holidays as $name => $date) { + $holidays = array_merge($holidays, $this->adjustForWeekend($name, $date)); + } + + return $holidays; } /** diff --git a/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays_2024.snap b/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays.snap similarity index 100% rename from tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays_2024.snap rename to tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays.snap From 392c3eb2afc013bae0d4f18d49af2c3f29436be0 Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sun, 21 Jan 2024 18:27:03 +0200 Subject: [PATCH 04/20] Rename holiday --- src/Countries/Egypt.php | 2 +- .../Countries/EgyptTest/it_can_calculate_egypt_holidays.snap | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php index 468b33445..e01b92cdb 100644 --- a/src/Countries/Egypt.php +++ b/src/Countries/Egypt.php @@ -73,7 +73,7 @@ private function getFixedHolidays(int $year): array 'Revolution Day 2011' => CarbonImmutable::create($year, 1, 25), 'Sinai Liberation Day' => CarbonImmutable::create($year, 4, 25), 'Labour Day' => CarbonImmutable::create($year, 5, 1), - 'June 30 Revolution' => CarbonImmutable::create($year, 6, 30), + 'June 30 Revolution Day' => CarbonImmutable::create($year, 6, 30), 'Revolution Day' => CarbonImmutable::create($year, 7, 23), 'Armed Forces Day' => CarbonImmutable::create($year, 10, 6), 'Spring Festival' => $this->orthodoxEaster($year)->addDay()->toImmutable() diff --git a/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays.snap b/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays.snap index 8afa6ed3b..b7e2892e5 100644 --- a/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays.snap +++ b/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays.snap @@ -80,7 +80,7 @@ "date": "2024-06-21" }, { - "name": "June 30 Revolution", + "name": "June 30 Revolution Day", "date": "2024-06-30" }, { From 5136bffa318f8c317ebee3a112fbaead47a0e8b8 Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sun, 21 Jan 2024 18:29:39 +0200 Subject: [PATCH 05/20] Minor --- src/Countries/Egypt.php | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php index e01b92cdb..9b111f2cd 100644 --- a/src/Countries/Egypt.php +++ b/src/Countries/Egypt.php @@ -33,18 +33,6 @@ protected function variableHolidays(int $year): array { $orthodoxEaster = $this->orthodoxEaster($year); - $otherHolidays = [ - 'Coptic Good Friday' => $orthodoxEaster->subDays(2)->toImmutable(), - 'Coptic Holy Saturday' => $orthodoxEaster->subDays()->toImmutable(), - 'Coptic Easter Sunday' => $orthodoxEaster->toImmutable(), - 'Flooding of the Nile' => CarbonImmutable::create($year, 8, 15), - 'March Equinox' => CarbonImmutable::create($year, 3, 20), - 'June Solstice' => CarbonImmutable::create($year, 6, 21), - 'September Equinox' => CarbonImmutable::create($year, 9, 22), - 'Nayrouz' => CarbonImmutable::create($year, 9, 11), - 'December Solstice' => CarbonImmutable::create($year, 12, 21), - ]; - $hijriHolidays = [ 'Islamic New Year' => '01-01', 'Ashura' => '01-10', @@ -59,7 +47,17 @@ protected function variableHolidays(int $year): array 'Eid al-Adha Day 4' => '12-13', ]; - return array_merge($otherHolidays, $this->convertHijriToGregorianHolidays($hijriHolidays, $year)); + return array_merge([ + 'Coptic Good Friday' => $orthodoxEaster->subDays(2)->toImmutable(), + 'Coptic Holy Saturday' => $orthodoxEaster->subDays()->toImmutable(), + 'Coptic Easter Sunday' => $orthodoxEaster->toImmutable(), + 'Flooding of the Nile' => CarbonImmutable::create($year, 8, 15), + 'March Equinox' => CarbonImmutable::create($year, 3, 20), + 'June Solstice' => CarbonImmutable::create($year, 6, 21), + 'September Equinox' => CarbonImmutable::create($year, 9, 22), + 'Nayrouz' => CarbonImmutable::create($year, 9, 11), + 'December Solstice' => CarbonImmutable::create($year, 12, 21), + ], $this->convertHijriToGregorianHolidays($hijriHolidays, $year)); } /** From f2659cdd53ab4c98a719ba9b3bab483a9cf1a77a Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sun, 21 Jan 2024 18:30:36 +0200 Subject: [PATCH 06/20] Minor --- src/Countries/Egypt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php index 9b111f2cd..ef11bce2f 100644 --- a/src/Countries/Egypt.php +++ b/src/Countries/Egypt.php @@ -154,7 +154,7 @@ private function adjustForWeekend(string $name, CarbonImmutable|false $date): ar // If the holiday falls on a weekend (Friday or Saturday), it is observed on the following Sunday $adjustedHolidays['Day off for ' . $name] = $date->next(CarbonInterface::SUNDAY); } elseif ($date->isSunday() || $date->isThursday()) { - // If the holiday falls on a Sunday, it is observed on the same day + // If the holiday falls on a Sunday or Thursday, it is observed on the same day $adjustedHolidays[$name] = $date; } else { // If the holiday falls on a weekday (Monday, Tuesday, Wednesday), it is observed on the following Thursday From 459726efef6c2adf0f8d0ba7e88345cb115dccbf Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sun, 21 Jan 2024 18:36:53 +0200 Subject: [PATCH 07/20] Pint --- src/Countries/Egypt.php | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php index ef11bce2f..4ab3b3390 100644 --- a/src/Countries/Egypt.php +++ b/src/Countries/Egypt.php @@ -14,7 +14,6 @@ public function countryCode(): string } /** - * @param int $year * @return array */ protected function allHolidays(int $year): array @@ -26,7 +25,6 @@ protected function allHolidays(int $year): array } /** - * @param int $year * @return array */ protected function variableHolidays(int $year): array @@ -61,7 +59,6 @@ protected function variableHolidays(int $year): array } /** - * @param int $year * @return array */ private function getFixedHolidays(int $year): array @@ -74,7 +71,7 @@ private function getFixedHolidays(int $year): array 'June 30 Revolution Day' => CarbonImmutable::create($year, 6, 30), 'Revolution Day' => CarbonImmutable::create($year, 7, 23), 'Armed Forces Day' => CarbonImmutable::create($year, 10, 6), - 'Spring Festival' => $this->orthodoxEaster($year)->addDay()->toImmutable() + 'Spring Festival' => $this->orthodoxEaster($year)->addDay()->toImmutable(), ]; foreach ($holidays as $name => $date) { @@ -85,8 +82,7 @@ private function getFixedHolidays(int $year): array } /** - * @param array $hijriHolidays - * @param int $year + * @param array $hijriHolidays * @return array */ private function convertHijriToGregorianHolidays(array $hijriHolidays, int $year): array @@ -100,15 +96,14 @@ private function convertHijriToGregorianHolidays(array $hijriHolidays, int $year * See: https://github.com/spatie/holidays/pull/56/ * --------------------------------------------------------------- */ - Hijri::setDefaultAdjustment(-1); - $currentHijriYear = (int)Hijri::convertToHijri($year . "-01-01")->format('Y'); + $currentHijriYear = (int) Hijri::convertToHijri($year.'-01-01')->format('Y'); $gregorianHolidays = []; foreach ($hijriHolidays as $holidayName => $hijriDate) { $gregorianDate = $this->getGregorianDateForHijriHoliday($hijriDate, $currentHijriYear, $year); - if (!is_null($gregorianDate)) { + if (! is_null($gregorianDate)) { $gregorianHolidays[$holidayName] = $gregorianDate; } } @@ -116,22 +111,16 @@ private function convertHijriToGregorianHolidays(array $hijriHolidays, int $year return $gregorianHolidays; } - /** - * @param string $hijriDate - * @param int $hijriYear - * @param int $gregorianYear - * @return CarbonImmutable|null - */ private function getGregorianDateForHijriHoliday(string $hijriDate, int $hijriYear, int $gregorianYear): ?CarbonImmutable { - list($month, $day) = explode('-', $hijriDate); - $currentYearDate = Hijri::convertToGregorian((int)$day, (int)$month, $hijriYear); + [$month, $day] = explode('-', $hijriDate); + $currentYearDate = Hijri::convertToGregorian((int) $day, (int) $month, $hijriYear); if ($currentYearDate->format('Y') == $gregorianYear) { return $currentYearDate->toImmutable(); } - $nextYearDate = Hijri::convertToGregorian((int)$day, (int)$month, $hijriYear + 1); + $nextYearDate = Hijri::convertToGregorian((int) $day, (int) $month, $hijriYear + 1); if ($nextYearDate->format('Y') == $gregorianYear) { return $nextYearDate->toImmutable(); } @@ -140,8 +129,6 @@ private function getGregorianDateForHijriHoliday(string $hijriDate, int $hijriYe } /** - * @param string $name - * @param CarbonImmutable|false $date * @return array */ private function adjustForWeekend(string $name, CarbonImmutable|false $date): array @@ -152,13 +139,13 @@ private function adjustForWeekend(string $name, CarbonImmutable|false $date): ar if ($date) { if ($date->isFriday() || $date->isSaturday()) { // If the holiday falls on a weekend (Friday or Saturday), it is observed on the following Sunday - $adjustedHolidays['Day off for ' . $name] = $date->next(CarbonInterface::SUNDAY); + $adjustedHolidays['Day off for '.$name] = $date->next(CarbonInterface::SUNDAY); } elseif ($date->isSunday() || $date->isThursday()) { // If the holiday falls on a Sunday or Thursday, it is observed on the same day $adjustedHolidays[$name] = $date; } else { // If the holiday falls on a weekday (Monday, Tuesday, Wednesday), it is observed on the following Thursday - $adjustedHolidays['Day off for ' . $name] = $date->next(CarbonInterface::THURSDAY); + $adjustedHolidays['Day off for '.$name] = $date->next(CarbonInterface::THURSDAY); } } From 08da226e43dc6d3ffad7eefdcf9c048c816b22fa Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sun, 21 Jan 2024 18:37:51 +0200 Subject: [PATCH 08/20] Rename test --- ...pt_holidays.snap => it_can_calculate_egyptian_holidays.snap} | 0 tests/Countries/EgyptTest.php | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/.pest/snapshots/Countries/EgyptTest/{it_can_calculate_egypt_holidays.snap => it_can_calculate_egyptian_holidays.snap} (100%) diff --git a/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays.snap b/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egyptian_holidays.snap similarity index 100% rename from tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays.snap rename to tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egyptian_holidays.snap diff --git a/tests/Countries/EgyptTest.php b/tests/Countries/EgyptTest.php index dff7bbf8a..842b8b4ef 100644 --- a/tests/Countries/EgyptTest.php +++ b/tests/Countries/EgyptTest.php @@ -5,7 +5,7 @@ use Carbon\CarbonImmutable; use Spatie\Holidays\Holidays; -it('can calculate egypt holidays', function () { +it('can calculate egyptian holidays', function () { CarbonImmutable::setTestNowAndTimezone('2024-01-01', 'Africa/Cairo'); $holidays = Holidays::for(country: 'eg')->get(); From 84af35e7c086fe17d73328060b7e7a1ce8116da8 Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Mon, 22 Jan 2024 11:39:27 +0200 Subject: [PATCH 09/20] Rename method --- src/Countries/Egypt.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php index 4ab3b3390..4d37dbaf9 100644 --- a/src/Countries/Egypt.php +++ b/src/Countries/Egypt.php @@ -18,7 +18,7 @@ public function countryCode(): string */ protected function allHolidays(int $year): array { - $fixedHolidays = $this->getFixedHolidays($year); + $fixedHolidays = $this->fixedHolidays($year); $variableHolidays = $this->variableHolidays($year); return array_merge($fixedHolidays, $variableHolidays); @@ -61,7 +61,7 @@ protected function variableHolidays(int $year): array /** * @return array */ - private function getFixedHolidays(int $year): array + private function fixedHolidays(int $year): array { $holidays = [ 'Coptic Christmas Day' => CarbonImmutable::create($year, 1, 7), From d66b66d1c231886ced77e2e15b820bb4727163e6 Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Mon, 22 Jan 2024 11:41:31 +0200 Subject: [PATCH 10/20] Early return --- src/Countries/Egypt.php | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php index 4d37dbaf9..40a42dd2a 100644 --- a/src/Countries/Egypt.php +++ b/src/Countries/Egypt.php @@ -135,20 +135,23 @@ private function adjustForWeekend(string $name, CarbonImmutable|false $date): ar { $adjustedHolidays = []; + if (! $date instanceof CarbonImmutable) { + return []; + } + // Explicitly define this logic to avoid timezone confusion on the CarbonInterface::next() method - if ($date) { - if ($date->isFriday() || $date->isSaturday()) { - // If the holiday falls on a weekend (Friday or Saturday), it is observed on the following Sunday - $adjustedHolidays['Day off for '.$name] = $date->next(CarbonInterface::SUNDAY); - } elseif ($date->isSunday() || $date->isThursday()) { - // If the holiday falls on a Sunday or Thursday, it is observed on the same day - $adjustedHolidays[$name] = $date; - } else { - // If the holiday falls on a weekday (Monday, Tuesday, Wednesday), it is observed on the following Thursday - $adjustedHolidays['Day off for '.$name] = $date->next(CarbonInterface::THURSDAY); - } + if ($date->isFriday() || $date->isSaturday()) { + // If the holiday falls on a weekend (Friday or Saturday), it is observed on the following Sunday + $adjustedHolidays['Day off for '.$name] = $date->next(CarbonInterface::SUNDAY); + } elseif ($date->isSunday() || $date->isThursday()) { + // If the holiday falls on a Sunday or Thursday, it is observed on the same day + $adjustedHolidays[$name] = $date; + } else { + // If the holiday falls on a weekday (Monday, Tuesday, Wednesday), it is observed on the following Thursday + $adjustedHolidays['Day off for '.$name] = $date->next(CarbonInterface::THURSDAY); } + return $adjustedHolidays; } } From a485e498a05b33d06b4597718a2f56c51faf5c69 Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Mon, 22 Jan 2024 11:51:10 +0200 Subject: [PATCH 11/20] Docblock --- src/Countries/Egypt.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php index 40a42dd2a..6b2f87288 100644 --- a/src/Countries/Egypt.php +++ b/src/Countries/Egypt.php @@ -116,6 +116,11 @@ private function getGregorianDateForHijriHoliday(string $hijriDate, int $hijriYe [$month, $day] = explode('-', $hijriDate); $currentYearDate = Hijri::convertToGregorian((int) $day, (int) $month, $hijriYear); + /** + * Converts a Hijri date to a Gregorian date and checks its alignment with the Gregorian year. + * Since a Hijri year is about 11 days shorter than a Gregorian year, we're checking + * if the converted date falls within the specified Gregorian year. + */ if ($currentYearDate->format('Y') == $gregorianYear) { return $currentYearDate->toImmutable(); } From b7262918d6cfa55eafced81b656bd64eb2189fac Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Mon, 22 Jan 2024 11:52:28 +0200 Subject: [PATCH 12/20] Docblock --- src/Countries/Egypt.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php index 6b2f87288..f493e3737 100644 --- a/src/Countries/Egypt.php +++ b/src/Countries/Egypt.php @@ -125,6 +125,11 @@ private function getGregorianDateForHijriHoliday(string $hijriDate, int $hijriYe return $currentYearDate->toImmutable(); } + /** + * If it does not fall within the specified Gregorian year, we're checking if the converted date + * falls within the next Gregorian year. This is to account for the fact that the Hijri year + * may start in the previous (that is to say, currently specified) Gregorian year. + */ $nextYearDate = Hijri::convertToGregorian((int) $day, (int) $month, $hijriYear + 1); if ($nextYearDate->format('Y') == $gregorianYear) { return $nextYearDate->toImmutable(); From 09ccd22a3d36f10de733bd19d603314c055e4a06 Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Mon, 22 Jan 2024 12:02:27 +0200 Subject: [PATCH 13/20] Add New Year's --- src/Countries/Egypt.php | 18 ++++++++++-------- .../it_can_calculate_egyptian_holidays.snap | 4 ++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php index f493e3737..c0ff6d1a6 100644 --- a/src/Countries/Egypt.php +++ b/src/Countries/Egypt.php @@ -21,7 +21,16 @@ protected function allHolidays(int $year): array $fixedHolidays = $this->fixedHolidays($year); $variableHolidays = $this->variableHolidays($year); - return array_merge($fixedHolidays, $variableHolidays); + return array_merge([ + // These are fixed, but seasonal holidays that aren't observed in Egypt + 'New Year\'s Day' => CarbonImmutable::create($year, 1, 1), + 'Flooding of the Nile' => CarbonImmutable::create($year, 8, 15), + 'March Equinox' => CarbonImmutable::create($year, 3, 20), + 'June Solstice' => CarbonImmutable::create($year, 6, 21), + 'September Equinox' => CarbonImmutable::create($year, 9, 22), + 'Nayrouz' => CarbonImmutable::create($year, 9, 11), + 'December Solstice' => CarbonImmutable::create($year, 12, 21), + ], $fixedHolidays, $variableHolidays); } /** @@ -49,12 +58,6 @@ protected function variableHolidays(int $year): array 'Coptic Good Friday' => $orthodoxEaster->subDays(2)->toImmutable(), 'Coptic Holy Saturday' => $orthodoxEaster->subDays()->toImmutable(), 'Coptic Easter Sunday' => $orthodoxEaster->toImmutable(), - 'Flooding of the Nile' => CarbonImmutable::create($year, 8, 15), - 'March Equinox' => CarbonImmutable::create($year, 3, 20), - 'June Solstice' => CarbonImmutable::create($year, 6, 21), - 'September Equinox' => CarbonImmutable::create($year, 9, 22), - 'Nayrouz' => CarbonImmutable::create($year, 9, 11), - 'December Solstice' => CarbonImmutable::create($year, 12, 21), ], $this->convertHijriToGregorianHolidays($hijriHolidays, $year)); } @@ -161,7 +164,6 @@ private function adjustForWeekend(string $name, CarbonImmutable|false $date): ar $adjustedHolidays['Day off for '.$name] = $date->next(CarbonInterface::THURSDAY); } - return $adjustedHolidays; } } diff --git a/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egyptian_holidays.snap b/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egyptian_holidays.snap index b7e2892e5..2bd487894 100644 --- a/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egyptian_holidays.snap +++ b/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egyptian_holidays.snap @@ -1,4 +1,8 @@ [ + { + "name": "New Year's Day", + "date": "2024-01-01" + }, { "name": "Coptic Christmas Day", "date": "2024-01-07" From 005220ef29053176d6dd5901eaad5732368ffb27 Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Mon, 22 Jan 2024 13:25:21 +0200 Subject: [PATCH 14/20] Minor --- src/Countries/Egypt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php index c0ff6d1a6..21ee998f0 100644 --- a/src/Countries/Egypt.php +++ b/src/Countries/Egypt.php @@ -117,13 +117,13 @@ private function convertHijriToGregorianHolidays(array $hijriHolidays, int $year private function getGregorianDateForHijriHoliday(string $hijriDate, int $hijriYear, int $gregorianYear): ?CarbonImmutable { [$month, $day] = explode('-', $hijriDate); - $currentYearDate = Hijri::convertToGregorian((int) $day, (int) $month, $hijriYear); /** * Converts a Hijri date to a Gregorian date and checks its alignment with the Gregorian year. * Since a Hijri year is about 11 days shorter than a Gregorian year, we're checking * if the converted date falls within the specified Gregorian year. */ + $currentYearDate = Hijri::convertToGregorian((int) $day, (int) $month, $hijriYear); if ($currentYearDate->format('Y') == $gregorianYear) { return $currentYearDate->toImmutable(); } From b87ec3fd475c51dab2ae634b142907965493cec5 Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sat, 3 Feb 2024 18:05:08 +0200 Subject: [PATCH 15/20] Add holidays statically/Turkey solution --- src/Countries/Egypt.php | 337 +++++++++++++++++++++++++++++++--------- 1 file changed, 265 insertions(+), 72 deletions(-) diff --git a/src/Countries/Egypt.php b/src/Countries/Egypt.php index 21ee998f0..52ec78672 100644 --- a/src/Countries/Egypt.php +++ b/src/Countries/Egypt.php @@ -4,10 +4,226 @@ use Carbon\CarbonImmutable; use Carbon\CarbonInterface; -use GeniusTS\HijriDate\Hijri; +use RuntimeException; class Egypt extends Country { + protected const EID_AL_FITR_HOLIDAYS = [ + 2005 => '11-04', + 2006 => '10-24', + 2007 => '10-13', + 2008 => '10-02', + 2009 => '09-21', + 2010 => '09-10', + 2011 => '08-30', + 2012 => '08-19', + 2013 => '08-08', + 2014 => '07-28', + 2015 => '07-17', + 2016 => '07-07', + 2017 => '06-26', + 2018 => '06-15', + 2019 => '06-05', + 2020 => '05-24', + 2021 => '05-13', + 2022 => '05-02', + 2023 => '04-20', + 2024 => '04-10', + 2025 => '03-31', + 2026 => '03-21', + 2027 => '03-10', + 2028 => '02-27', + 2029 => '02-15', + 2030 => '02-04', + 2031 => '01-25', + 2032 => '01-15', + 2033 => '01-03', + 2034 => '12-13', + 2035 => '12-02', + 2036 => '11-20', + 2037 => '11-09', + ]; + + protected const ARAFAT_DAY_HOLIDAYS = [ + 2005 => '01-21', + 2006 => '01-10', + 2007 => '01-01', + 2008 => '12-09', + 2009 => '11-26', + 2010 => '11-15', + 2011 => '11-05', + 2012 => '10-25', + 2013 => '10-15', + 2014 => '10-04', + 2015 => '09-23', + 2016 => '09-11', + 2017 => '08-31', + 2018 => '08-20', + 2019 => '08-10', + 2020 => '07-30', + 2021 => '07-19', + 2022 => '07-09', + 2023 => '06-27', + 2024 => '06-16', + 2025 => '06-06', + 2026 => '05-26', + 2027 => '05-16', + 2028 => '05-05', + 2029 => '04-24', + 2030 => '04-13', + 2031 => '04-02', + 2032 => '03-21', + 2033 => '03-11', + 2034 => '03-01', + 2035 => '02-18', + 2036 => '02-07', + 2037 => '01-26', + ]; + + protected const EID_AL_ADHA_HOLIDAYS = [ + 2005 => '01-22', + 2006 => '01-11', + 2007 => '01-02', + 2008 => '12-10', + 2009 => '11-27', + 2010 => '11-16', + 2011 => '11-06', + 2012 => '10-26', + 2013 => '10-16', + 2014 => '10-05', + 2015 => '09-24', + 2016 => '09-12', + 2017 => '08-31', + 2018 => '08-21', + 2019 => '08-11', + 2020 => '07-31', + 2021 => '07-20', + 2022 => '07-09', + 2023 => '06-28', + 2024 => '06-17', + 2025 => '06-07', + 2026 => '05-27', + 2027 => '05-17', + 2028 => '05-06', + 2029 => '04-25', + 2030 => '04-14', + 2031 => '04-03', + 2032 => '03-22', + 2033 => '03-12', + 2034 => '03-02', + 2035 => '02-19', + 2036 => '02-08', + 2037 => '01-27', + ]; + + protected const ISLAMIC_NEW_YEAR_HOLIDAYS = [ + 2005 => '02-10', + 2006 => '01-31', + 2007 => '01-20', + 2008 => '01-10', + 2009 => '12-18', + 2010 => '12-07', + 2011 => '11-27', + 2012 => '11-15', + 2013 => '11-05', + 2014 => '10-25', + 2015 => '10-14', + 2016 => '10-03', + 2017 => '09-22', + 2018 => '09-11', + 2019 => '08-31', + 2020 => '08-20', + 2021 => '08-09', + 2022 => '07-30', + 2023 => '07-19', + 2024 => '07-08', + 2025 => '06-06', + 2026 => '06-17', + 2027 => '06-07', + 2028 => '05-26', + 2029 => '05-15', + 2030 => '05-05', + 2031 => '04-24', + 2032 => '04-12', + 2033 => '04-01', + 2034 => '03-22', + 2035 => '03-12', + 2036 => '02-29', + 2037 => '02-17', + ]; + + protected const ASHURA_HOLIDAYS = [ + 2005 => '02-19', + 2006 => '02-09', + 2007 => '01-29', + 2008 => '01-19', + 2009 => '12-27', + 2010 => '12-16', + 2011 => '12-06', + 2012 => '11-25', + 2013 => '11-15', + 2014 => '11-04', + 2015 => '10-24', + 2016 => '10-13', + 2017 => '10-02', + 2018 => '09-21', + 2019 => '09-10', + 2020 => '08-30', + 2021 => '08-19', + 2022 => '08-08', + 2023 => '07-28', + 2024 => '07-17', + 2025 => '07-07', + 2026 => '06-26', + 2027 => '06-15', + 2028 => '06-04', + 2029 => '05-24', + 2030 => '05-13', + 2031 => '05-02', + 2032 => '04-20', + 2033 => '04-10', + 2034 => '03-30', + 2035 => '03-19', + 2036 => '03-08', + 2037 => '02-25', + ]; + + protected const PROPHET_MUHAMMAD_BIRTHDAY_HOLIDAYS = [ + 2005 => '04-21', + 2006 => '04-11', + 2007 => '03-31', + 2008 => '03-20', + 2009 => '03-09', + 2010 => '02-26', + 2011 => '02-16', + 2012 => '02-05', + 2013 => '01-24', + 2014 => '01-13', + 2015 => '12-23', + 2016 => '12-12', + 2017 => '12-01', + 2018 => '11-20', + 2019 => '11-09', + 2020 => '10-29', + 2021 => '10-21', + 2022 => '10-08', + 2023 => '09-28', + 2024 => '09-16', + 2025 => '09-06', + 2026 => '08-26', + 2027 => '08-15', + 2028 => '08-04', + 2029 => '07-25', + 2030 => '07-14', + 2031 => '07-03', + 2032 => '06-21', + 2033 => '06-10', + 2034 => '05-31', + 2035 => '05-21', + 2036 => '05-09', + 2037 => '04-29', + ]; + public function countryCode(): string { return 'eg'; @@ -40,25 +256,59 @@ protected function variableHolidays(int $year): array { $orthodoxEaster = $this->orthodoxEaster($year); - $hijriHolidays = [ - 'Islamic New Year' => '01-01', - 'Ashura' => '01-10', - 'Birthday of the Prophet Muhammad' => '03-12', - 'Eid al-Fitr' => '10-01', - 'Eid al-Fitr Day 2' => '10-02', - 'Eid al-Fitr Day 3' => '10-03', - 'Arafat Day' => '12-09', - 'Eid al-Adha' => '12-10', - 'Eid al-Adha Day 2' => '12-11', - 'Eid al-Adha Day 3' => '12-12', - 'Eid al-Adha Day 4' => '12-13', - ]; + $eidAlFitrDates = $this->getIslamicHolidayDatesForYear(self::EID_AL_FITR_HOLIDAYS, $year, 'Eid al-Fitr', 3); + $eidAlAdhaDates = $this->getIslamicHolidayDatesForYear(self::EID_AL_ADHA_HOLIDAYS, $year, 'Eid al-Adha', 4); + $arafatDayDates = $this->getIslamicHolidayDatesForYear(self::ARAFAT_DAY_HOLIDAYS, $year, 'Arafat Day'); + $islamicNewYearDates = $this->getIslamicHolidayDatesForYear(self::ISLAMIC_NEW_YEAR_HOLIDAYS, $year, 'Islamic New Year'); + $ashuraDates = $this->getIslamicHolidayDatesForYear(self::ASHURA_HOLIDAYS, $year, 'Ashura'); + $prophetMuhammadBirthdayDates = $this->getIslamicHolidayDatesForYear(self::PROPHET_MUHAMMAD_BIRTHDAY_HOLIDAYS, $year, 'Birthday of the Prophet Muhammad'); return array_merge([ 'Coptic Good Friday' => $orthodoxEaster->subDays(2)->toImmutable(), 'Coptic Holy Saturday' => $orthodoxEaster->subDays()->toImmutable(), 'Coptic Easter Sunday' => $orthodoxEaster->toImmutable(), - ], $this->convertHijriToGregorianHolidays($hijriHolidays, $year)); + ], $eidAlFitrDates, $eidAlAdhaDates, $arafatDayDates, $islamicNewYearDates, $ashuraDates, $prophetMuhammadBirthdayDates); + } + + /** + * Prepare holiday dates for the given year. + * + * @param array $holidayDates Array mapping years to dates. + * @param int $year The year for which to prepare holiday dates. + * @param string $holidayName The name of the holiday. + * @param int $duration The duration of the holiday in days. + * @return array An array of holiday dates. + */ + private function getIslamicHolidayDatesForYear(array $holidayDates, int $year, string $holidayName, int $duration = 1): array + { + $dates = []; + + /** + * No reliable sources exist for Islamic holidays observed in Egypt prior to 2005. + * So we'll only calculate holidays from 2005 onwards. + * + * @see https://www.timeanddate.com/holidays/egypt + */ + if (isset($holidayDates[$year])) { + $startDay = CarbonImmutable::createFromFormat('Y-m-d', sprintf('%s-%s', $year, $holidayDates[$year])); + + if (! $startDay instanceof CarbonImmutable) { + throw new RuntimeException('Date could not be created.'); + } + + if ($duration === 1) { + // For single-day holidays, use the holiday name without "Day" + $dates[$holidayName] = $startDay; + } else { + // For multi-day holidays, append "Day N" for the second day onwards + for ($i = 0; $i < $duration; $i++) { + $dayLabel = $i === 0 ? $holidayName : sprintf('%s Day %d', $holidayName, $i + 1); + $dates[$dayLabel] = $startDay->addDays($i); + } + } + } + + return $dates; } /** @@ -84,63 +334,6 @@ private function fixedHolidays(int $year): array return $holidays; } - /** - * @param array $hijriHolidays - * @return array - */ - private function convertHijriToGregorianHolidays(array $hijriHolidays, int $year): array - { - /** - * --------------------------------------------------------------- - * Code Adaptation - * --------------------------------------------------------------- - * This strategy was adapted from PR #56. - * Original contribution by: YazidKHALDI - * See: https://github.com/spatie/holidays/pull/56/ - * --------------------------------------------------------------- - */ - Hijri::setDefaultAdjustment(-1); - - $currentHijriYear = (int) Hijri::convertToHijri($year.'-01-01')->format('Y'); - $gregorianHolidays = []; - - foreach ($hijriHolidays as $holidayName => $hijriDate) { - $gregorianDate = $this->getGregorianDateForHijriHoliday($hijriDate, $currentHijriYear, $year); - if (! is_null($gregorianDate)) { - $gregorianHolidays[$holidayName] = $gregorianDate; - } - } - - return $gregorianHolidays; - } - - private function getGregorianDateForHijriHoliday(string $hijriDate, int $hijriYear, int $gregorianYear): ?CarbonImmutable - { - [$month, $day] = explode('-', $hijriDate); - - /** - * Converts a Hijri date to a Gregorian date and checks its alignment with the Gregorian year. - * Since a Hijri year is about 11 days shorter than a Gregorian year, we're checking - * if the converted date falls within the specified Gregorian year. - */ - $currentYearDate = Hijri::convertToGregorian((int) $day, (int) $month, $hijriYear); - if ($currentYearDate->format('Y') == $gregorianYear) { - return $currentYearDate->toImmutable(); - } - - /** - * If it does not fall within the specified Gregorian year, we're checking if the converted date - * falls within the next Gregorian year. This is to account for the fact that the Hijri year - * may start in the previous (that is to say, currently specified) Gregorian year. - */ - $nextYearDate = Hijri::convertToGregorian((int) $day, (int) $month, $hijriYear + 1); - if ($nextYearDate->format('Y') == $gregorianYear) { - return $nextYearDate->toImmutable(); - } - - return null; - } - /** * @return array */ From c30b89bd97f29db8402f96653617593dcdfd3be5 Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sat, 3 Feb 2024 18:25:03 +0200 Subject: [PATCH 16/20] Fix translations --- lang/egypt/ar/holidays.json | 42 +++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/lang/egypt/ar/holidays.json b/lang/egypt/ar/holidays.json index 2ca7af8d3..646f82ada 100644 --- a/lang/egypt/ar/holidays.json +++ b/lang/egypt/ar/holidays.json @@ -1,23 +1,33 @@ { - "New Year\n's Day": "يوم رأس السنة", - "Coptic Christmas": "عيد الميلاد القبطي", - "Revolution Day January 25": "عيد ثورة 25 يناير", + "New Year\\'s Day": "يوم رأس السنة", + "Coptic Christmas Day": "عيد الميلاد المجيد", + "Revolution Day 2011": "ثورة ٢٥ يناير وعيد الشرطة", "March Equinox": "اعتدال مارس", - "Sinai Liberation": "تحرير سيناء", - "Labor": "العمل", - "Coptic Good": "الصالح القبطي", - "Coptic Holy": "المقدس القبطي", - "Coptic Easter": "عيد الفصح القبطي", - "Spring Festival": "مهرجان الربيع", + "Sinai Liberation Day": "عيد تحرير سيناء (٢٥ أبريل ١٩٨٢)", + "Labour Day": "عيد العمال", + "Coptic Good Friday": "الصالح القبطي", + "Coptic Holy Saturday": "المقدس القبطي", + "Coptic Easter Sunday": "عيد الفصح القبطي", + "Spring Festival": "عيد شم النسيم", "June Solstice": "انقلاب يونيو", - "June 30 Revolution": "ثورة 30 يونيو", - "Day off for June 30 Revolution": "يوم عطلة بمناسبة ثورة 30 يونيو", - "Revolution Day July 23": "عيد ثورة 23 يوليو", - "Day off for Revolution Day July 23": "يوم عطلة بمناسبة عيد ثورة 23 يوليو", + "June 30 Revolution Day": "عيد ثورة 30 يونيو", + "Day off for June 30 Revolution Day": "بمناسبة عيد ثورة 30 يونيو", + "Revolution Day": "عيد ثورة 23 يوليو", + "Day off for Revolution Day": "بمناسبة عيد ثورة 23 يوليو", "Flooding of the Nile": "فيضان النيل", "Nayrouz": "النيروز", "September Equinox": "الاعتدال في سبتمبر", - "Armed Forces": "القوات المسلحة", + "Armed Forces": "عيد القوات المسلحة (٦ أكتوبر ١٩٧٣)", "Day off for Armed Forces": "يوم عطلة للقوات المسلحة", - "December Solstice": "الانقلاب الشمسي في ديسمبر" -} \ No newline at end of file + "December Solstice": "الانقلاب الشمسي في ديسمبر", + "Eid al-Fitr": "عيد الفطر المبارك", + "Eid al-Fitr Day 2": "عيد الفطر المبارك", + "Eid al-Fitr Day 3": "عيد الفطر المبارك", + "Eid al-Adha": "عيد الأضحى المبارك", + "Eid al-Adha Day 2": "عيد الأضحى المبارك", + "Eid al-Adha Day 3": "عيد الأضحى المبارك", + "Eid al-Adha Day 4": "عيد الأضحى المبارك", + "Islamic New Year (Muharram)": "رأس السنة الهجرية", + "Birthday of the Prophet Muhammad": "المولد النبوي الشريف", + "Arafat Day": "يوم عرفة (وقفة عيد الأضحى)" +} From 0ca59aa4e51bc2cf97c18a3d07ffcb7e295d7a2b Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sat, 3 Feb 2024 18:51:20 +0200 Subject: [PATCH 17/20] Minor --- lang/egypt/ar/holidays.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/egypt/ar/holidays.json b/lang/egypt/ar/holidays.json index 646f82ada..3c835626f 100644 --- a/lang/egypt/ar/holidays.json +++ b/lang/egypt/ar/holidays.json @@ -17,7 +17,7 @@ "Flooding of the Nile": "فيضان النيل", "Nayrouz": "النيروز", "September Equinox": "الاعتدال في سبتمبر", - "Armed Forces": "عيد القوات المسلحة (٦ أكتوبر ١٩٧٣)", + "Armed Forces Day": "عيد القوات المسلحة (٦ أكتوبر ١٩٧٣)", "Day off for Armed Forces": "يوم عطلة للقوات المسلحة", "December Solstice": "الانقلاب الشمسي في ديسمبر", "Eid al-Fitr": "عيد الفطر المبارك", From 0057a7279e72e3827dcf5e6139b882b357c0791d Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sat, 3 Feb 2024 18:55:59 +0200 Subject: [PATCH 18/20] Remove snapshot --- .../it_can_calculate_egypt_holidays.snap | 86 ------------------- 1 file changed, 86 deletions(-) delete mode 100644 tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays.snap diff --git a/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays.snap b/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays.snap deleted file mode 100644 index 97a3a8144..000000000 --- a/tests/.pest/snapshots/Countries/EgyptTest/it_can_calculate_egypt_holidays.snap +++ /dev/null @@ -1,86 +0,0 @@ -[ - { - "name": "New Year's Day", - "date": "2024-01-01" - }, - { - "name": "Coptic Christmas", - "date": "2024-01-07" - }, - { - "name": "Revolution Day January 25", - "date": "2024-01-25" - }, - { - "name": "March Equinox", - "date": "2024-03-20" - }, - { - "name": "Sinai Liberation", - "date": "2024-04-25" - }, - { - "name": "Labor", - "date": "2024-05-01" - }, - { - "name": "Coptic Good", - "date": "2024-05-03" - }, - { - "name": "Coptic Holy", - "date": "2024-05-04" - }, - { - "name": "Coptic Easter", - "date": "2024-05-05" - }, - { - "name": "Spring Festival", - "date": "2024-05-06" - }, - { - "name": "June Solstice", - "date": "2024-06-20" - }, - { - "name": "June 30 Revolution", - "date": "2024-06-30" - }, - { - "name": "Day off for June 30 Revolution", - "date": "2024-07-04" - }, - { - "name": "Revolution Day July 23", - "date": "2024-07-23" - }, - { - "name": "Day off for Revolution Day July 23", - "date": "2024-07-25" - }, - { - "name": "Flooding of the Nile", - "date": "2024-08-15" - }, - { - "name": "Nayrouz", - "date": "2024-09-11" - }, - { - "name": "September Equinox", - "date": "2024-09-22" - }, - { - "name": "Armed Forces", - "date": "2024-10-06" - }, - { - "name": "Day off for Armed Forces", - "date": "2024-10-10" - }, - { - "name": "December Solstice", - "date": "2024-12-21" - } -] \ No newline at end of file From 00fe09e28ddb2b0fc20e9d257558a126c0640a9e Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sat, 3 Feb 2024 18:57:54 +0200 Subject: [PATCH 19/20] This can be misunderstood --- lang/egypt/ar/holidays.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/egypt/ar/holidays.json b/lang/egypt/ar/holidays.json index 3c835626f..d735a5ef9 100644 --- a/lang/egypt/ar/holidays.json +++ b/lang/egypt/ar/holidays.json @@ -9,7 +9,7 @@ "Coptic Holy Saturday": "المقدس القبطي", "Coptic Easter Sunday": "عيد الفصح القبطي", "Spring Festival": "عيد شم النسيم", - "June Solstice": "انقلاب يونيو", + "June Solstice": "الانقلاب الشمسي في يونيو", "June 30 Revolution Day": "عيد ثورة 30 يونيو", "Day off for June 30 Revolution Day": "بمناسبة عيد ثورة 30 يونيو", "Revolution Day": "عيد ثورة 23 يوليو", From bd9b78032db56397c5c6f31f095eac2efe1b9f66 Mon Sep 17 00:00:00 2001 From: Wessam Ahmed Date: Sat, 3 Feb 2024 19:06:50 +0200 Subject: [PATCH 20/20] Add more translations --- lang/egypt/ar/holidays.json | 6 +++--- lang/egypt/en/holidays.json | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 lang/egypt/en/holidays.json diff --git a/lang/egypt/ar/holidays.json b/lang/egypt/ar/holidays.json index d735a5ef9..efdf7779f 100644 --- a/lang/egypt/ar/holidays.json +++ b/lang/egypt/ar/holidays.json @@ -1,5 +1,5 @@ { - "New Year\\'s Day": "يوم رأس السنة", + "New Year\\'s Day": "رأس السنة الميلادية", "Coptic Christmas Day": "عيد الميلاد المجيد", "Revolution Day 2011": "ثورة ٢٥ يناير وعيد الشرطة", "March Equinox": "اعتدال مارس", @@ -18,7 +18,7 @@ "Nayrouz": "النيروز", "September Equinox": "الاعتدال في سبتمبر", "Armed Forces Day": "عيد القوات المسلحة (٦ أكتوبر ١٩٧٣)", - "Day off for Armed Forces": "يوم عطلة للقوات المسلحة", + "Day off for Armed Forces Day": "يوم عطلة للقوات المسلحة", "December Solstice": "الانقلاب الشمسي في ديسمبر", "Eid al-Fitr": "عيد الفطر المبارك", "Eid al-Fitr Day 2": "عيد الفطر المبارك", @@ -27,7 +27,7 @@ "Eid al-Adha Day 2": "عيد الأضحى المبارك", "Eid al-Adha Day 3": "عيد الأضحى المبارك", "Eid al-Adha Day 4": "عيد الأضحى المبارك", - "Islamic New Year (Muharram)": "رأس السنة الهجرية", + "Islamic New Year": "رأس السنة الهجرية", "Birthday of the Prophet Muhammad": "المولد النبوي الشريف", "Arafat Day": "يوم عرفة (وقفة عيد الأضحى)" } diff --git a/lang/egypt/en/holidays.json b/lang/egypt/en/holidays.json new file mode 100644 index 000000000..a503639ee --- /dev/null +++ b/lang/egypt/en/holidays.json @@ -0,0 +1,33 @@ +{ + "New Year\\'s Day": "New Year\\'s Day", + "Coptic Christmas Day": "Coptic Christmas Day", + "Revolution Day 2011": "Revolution Day 2011", + "March Equinox": "March Equinox", + "Sinai Liberation Day": "Sinai Liberation Day", + "Labour Day": "Labour Day", + "Coptic Good Friday": "Coptic Good Friday", + "Coptic Holy Saturday": "Coptic Holy Saturday", + "Coptic Easter Sunday": "Coptic Easter Sunday", + "Spring Festival": "Spring Festival", + "June Solstice": "June Solstice", + "June 30 Revolution Day": "June 30 Revolution Day", + "Day off for June 30 Revolution Day": "Day off for June 30 Revolution Day", + "Revolution Day": "Revolution Day", + "Day off for Revolution Day": "Day off for Revolution Day", + "Flooding of the Nile": "Flooding of the Nile", + "Nayrouz": "Nayrouz", + "September Equinox": "September Equinox", + "Armed Forces Day": "Armed Forces Day", + "Day off for Armed Forces Day": "Day off for Armed Forces", + "December Solstice": "December Solstice", + "Eid al-Fitr": "Eid al-Fitr", + "Eid al-Fitr Day 2": "Eid al-Fitr", + "Eid al-Fitr Day 3": "Eid al-Fitr", + "Eid al-Adha": "Eid al-Adha", + "Eid al-Adha Day 2": "Eid al-Adha", + "Eid al-Adha Day 3": "Eid al-Adha", + "Eid al-Adha Day 4": "Eid al-Adha", + "Islamic New Year": "Islamic New Year (Muharram)", + "Birthday of the Prophet Muhammad": "Birthday of the Prophet Muhammad", + "Arafat Day": "Arafat Day", +}