-
-
Notifications
You must be signed in to change notification settings - Fork 197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Moroccan Holidays #56
Changes from all commits
5bb1349
3f81a1c
66015df
dc812c7
7c41e21
b1ed9f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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": "تاني ايام عيد الأضحى" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
<?php | ||
|
||
namespace Spatie\Holidays\Countries; | ||
|
||
use Carbon\CarbonImmutable; | ||
use Spatie\Holidays\Concerns\Translatable; | ||
use Spatie\Holidays\Contracts\HasTranslations; | ||
use Spatie\Holidays\Exceptions\InvalidYear; | ||
|
||
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([ | ||
'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', | ||
'Green March' => '11-06', | ||
'Independence Day' => '11-18', | ||
], $this->variableHolidays($year)); | ||
} | ||
|
||
/** @return array<string, CarbonImmutable> */ | ||
protected function variableHolidays(int $year): array | ||
{ | ||
// Calculate the current Hijri year based on the Gregorian year | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can have a look at other Islamic countries and how their lunar based holidays are resolved. For example: Turkey, Bahrein and Egypt. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've reviewed the other contributions, and it seems they've hardcoded the expected dates of Islamic holidays. Personally, I don't find that approach ideal. Instead, I opted to use a date converter for more dynamism. While it may not be 100% accurate, it offers flexibility. If you still prefer the hardcoded holiday expectation dates, I'm willing to make the change tonight. |
||
$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 | ||
* occur based on the lunar calendar sequence. The order listed reflects the chronological occurrence | ||
* of these holidays throughout the year. | ||
*/ | ||
|
||
// 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) { | ||
[$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--, (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'])); | ||
} | ||
|
||
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{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(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; | ||
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 [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do I have the right to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is a necessary feature to not exclude half the holidays from Muslim countries There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not really familiar with this. Could you shortly explain what this package would do and how we could benefit from it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The geniusts/hijri-dates package is a reliable PHP library designed to facilitate the conversion between Gregorian and Hijri dates. In our case, it can be incredibly useful for handling Islamic holidays that are based on the Hijri calendar. The Islamic calendar follows a lunar system, which means that its months and years are determined by the moon's phases. This leads to variations in the lengths of months and the occurrence of Islamic holidays. By integrating this package, we gain the ability to accurately convert dates between the Gregorian and Hijri calendars. I am currently in the process of testing the package to ensure its efficacy. I have a slight doubt about its accuracy, but my friend from the Maldives has used it in his PR#63. I will conduct thorough testing today to evaluate its performance and accuracy. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @Nielsvanpach, I utilized the geniusts/hijri-dates package to compute Islamic holidays for Morocco. I have included tests for the years 2023, 2024, 2025, and 2026. The results match the date converter provided by the Minister of Religious Endowments and Islamic Affairs. Please note that it's not possible to predict Islamic holidays with 100% certainty. Ministry observers use the naked-eye observation of the New Moon at the end of each lunar month to determine if the current month is 29 or 30 days, impacting the declaration of the new month. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for that! Just for clarity; do countries with Islamic public holidays all have the same dates for them? So is If so, is it possible to not limit this to only Morocco, but make the calculations accessible for all countries with Islamic holidays? I would prefer a single implementation for those calculations instead of it being scattered all around the codebase for different countries. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Nielsvanpach It is common for Islamic countries but the phase of the moon is not the same everywhere; For example Also, the duration of days off may differ between countries, Some may take a week and some may take 2 days. Btw, this #90 is also making use of the same package. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The topic is more intricate than it seems, and there are ongoing debates in Islamic countries. There are two main differences between countries:
In conclusion, having the same date for all countries is challenging, and achieving 100% accuracy in calculations is difficult because each country has its own protocol for the observation of the new moon. PS: I fixed the PHPStan failure. |
||
'year' => (int) $y, | ||
'month' => (int) $m, | ||
'day' => (int) $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 float 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); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
[ | ||
{ | ||
"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": "Green March", | ||
"date": "2023-11-06" | ||
}, | ||
{ | ||
"name": "Independence Day", | ||
"date": "2023-11-18" | ||
} | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
[ | ||
{ | ||
"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": "Green March", | ||
"date": "2024-11-06" | ||
}, | ||
{ | ||
"name": "Independence Day", | ||
"date": "2024-11-18" | ||
} | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
[ | ||
{ | ||
"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": "Green March", | ||
"date": "2025-11-06" | ||
}, | ||
{ | ||
"name": "Independence Day", | ||
"date": "2025-11-18" | ||
} | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this be Arabic by default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanx for the review
In fact, I assumed that the Package would be used globally and therefore set English as the default language.