diff --git a/composer.json b/composer.json index 4a09fcf..f224718 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,8 @@ "description": "Carbon mixin to handle business days", "type": "library", "require": { - "nesbot/carbon": "^1.26.2 || ^2.0" + "nesbot/carbon": "^1.26.2 || ^2.0", + "ext-calendar": "*" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.0" diff --git a/prepare-names-files.php b/prepare-names-files.php new file mode 100644 index 0000000..dc45ba6 --- /dev/null +++ b/prepare-names-files.php @@ -0,0 +1,29 @@ +/m', function ($match) use ($length) { + $key = $match[1]; + $spaces = str_repeat(' ', $length - strlen($key)); + + return " '$key'$spaces =>"; + }, $data); + file_put_contents($file, "getHolidayId() !== false; }; } + + /** + * Get the holidays in the given language. + * + * @return \Closure + */ + public function getHolidayNamesDictionary() + { + $mixin = $this; + $defaultLocale = static::DEFAULT_HOLIDAY_LOCALE; + + return function ($locale) use ($mixin, $defaultLocale) { + if (isset($mixin->holidayNames[$locale])) { + return $mixin->holidayNames[$locale] ?: $mixin->holidayNames[$defaultLocale]; + } + + $file = __DIR__."/../HolidayNames/$locale.php"; + if (!file_exists($file)) { + $mixin->holidayNames[$locale] = false; + $locale = $defaultLocale; + $file = __DIR__."/../HolidayNames/$locale.php"; + } + + return $mixin->holidayNames[$locale] = include $file; + }; + } + + /** + * Get the name of the current holiday (using the locale given in parameter or the current date locale) + * or false if it's not a holiday. + * + * @return \Closure + */ + public function getHolidayName() + { + $carbonClass = static::getCarbonClass(); + $getThisOrToday = static::getThisOrToday(); + $swap = static::swapDateTimeParam(); + $dictionary = $this->getHolidayNamesDictionary(); + + return function ($locale = null, $self = null) use ($carbonClass, $getThisOrToday, $swap, $dictionary) { + $swap($locale, $self); + + /** @var Carbon|BusinessDay $self */ + $self = $getThisOrToday($self, isset($this) ? $this : null); + $key = $self->getHolidayId(); + + if ($key === false) { + return false; + } + + if (!$locale) { + $locale = (isset($self->locale) ? $self->locale : $carbonClass::getLocale()) ?: 'en'; + } + + /* @var string $key */ + $names = $dictionary(preg_replace('/^([^_-]+)([_-].*)$/', '$1', $locale)); + + return isset($names[$key]) ? $names[$key] : 'Unknown'; + }; + } } diff --git a/src/Cmixin/BusinessDay/HolidayObserver.php b/src/Cmixin/BusinessDay/HolidayObserver.php index b99fc3e..7be5e44 100644 --- a/src/Cmixin/BusinessDay/HolidayObserver.php +++ b/src/Cmixin/BusinessDay/HolidayObserver.php @@ -194,13 +194,10 @@ public function isObservedHoliday() { $mixin = $this; $getThisOrToday = static::getThisOrToday(); - $carbonClass = static::getCarbonClass(); + $swap = static::swapDateTimeParam(); - return function ($name = null, $self = null) use ($mixin, $getThisOrToday, $carbonClass) { - if ($name instanceof \DateTime || $name instanceof \DateTimeInterface) { - $self = $carbonClass::instance($name); - $name = null; - } + return function ($name = null, $self = null) use ($mixin, $getThisOrToday, $swap) { + $swap($name, $self); if (!$name) { /** @var Carbon|BusinessDay $self */ diff --git a/src/Cmixin/BusinessDay/MixinBase.php b/src/Cmixin/BusinessDay/MixinBase.php index 9ac2c79..70d62af 100644 --- a/src/Cmixin/BusinessDay/MixinBase.php +++ b/src/Cmixin/BusinessDay/MixinBase.php @@ -40,4 +40,24 @@ public function getThisOrToday() return $self ?: $staticClass::today(); }; } + + public function isDateTimeInstance() + { + return function ($value) { + return $value instanceof \DateTime || $value instanceof \DateTimeInterface; + }; + } + + public function swapDateTimeParam() + { + $check = static::isDateTimeInstance(); + $staticClass = static::getCarbonClass(); + + return function (&$date, &$target, $defaultValue = null) use ($check, $staticClass) { + if ($check($date)) { + $target = $staticClass::instance($date); + $date = $defaultValue; + } + }; + } } diff --git a/src/Cmixin/HolidayNames/en.php b/src/Cmixin/HolidayNames/en.php new file mode 100644 index 0000000..afa6154 --- /dev/null +++ b/src/Cmixin/HolidayNames/en.php @@ -0,0 +1,32 @@ + 'Armistice 1918', + 'ascension' => 'Ascension', + 'assumption' => 'Assomption', + 'christmas' => 'Christmas', + 'christmas-next-day' => 'Christmas next day', + 'easter' => 'Easter', + 'easter-monday' => 'Easter Monday', + 'epiphany' => 'Epiphany', + 'good-friday' => 'Good Friday', + 'independence-day' => 'Independence Day', + 'labor-day' => 'Labor Day', + 'liberation-day' => 'Liberation Day', + 'memorial-day' => 'Memorial Day', + 'mlk-day' => 'Martin Luther King Jr. Day', + 'national-day' => 'National Day', + 'new-year' => 'New Year', + 'new-year-next-day' => 'New Year next day', + 'pentecost' => 'Pentecost', + 'pentecost-monday' => 'Pentecost Monday', + 'preseren-day' => 'Prešeren Day', + 'rebellion-day' => 'Rebellion Day', + 'reformation-day' => 'Reformation Day', + 'royal-day' => 'Royal Day', + 'thanksgiving' => 'Thanksgiving', + 'toussaint' => 'Toussaint', + 'vacation-day' => 'Vacation Day', + 'vacation-next-day' => 'Vacation Day next day', + 'victory-1945' => 'Victory 1945', +); diff --git a/src/Cmixin/HolidayNames/fr.php b/src/Cmixin/HolidayNames/fr.php new file mode 100644 index 0000000..29cc800 --- /dev/null +++ b/src/Cmixin/HolidayNames/fr.php @@ -0,0 +1,32 @@ + 'Armistice 1918', + 'ascension' => 'Ascension', + 'assumption' => 'Assomption', + 'christmas' => 'Noël', + 'christmas-next-day' => 'Saint Etienne', + 'easter' => 'Pâques', + 'easter-monday' => 'Lundi de Pâques', + 'epiphany' => 'Épiphanie', + 'good-friday' => 'Vendredi Saint', + 'independence-day' => 'Indépendance', + 'labor-day' => 'Fête du travail', + 'liberation-day' => 'Libération', + 'memorial-day' => 'Jour commémoratif', + 'mlk-day' => 'Jour de Martin Luther King', + 'national-day' => 'Fête nationale', + 'new-year' => 'Nouvel an', + 'new-year-next-day' => 'Lendemain du nouvel an', + 'pentecost' => 'Pentecôte', + 'pentecost-monday' => 'Lundi de Pentecôte', + 'preseren-day' => 'Jour de Prešeren', + 'rebellion-day' => 'Jour de la Rébellion', + 'reformation-day' => 'Jour de la Reformation', + 'royal-day' => 'Jour royal', + 'thanksgiving' => 'Thanksgiving', + 'toussaint' => 'Toussaint', + 'vacation-day' => 'Jour de vacances', + 'vacation-next-day' => 'Lendemain du jour de vacances', + 'victory-1945' => 'Victoire 1945', +); diff --git a/src/Cmixin/HolidayNames/nl.php b/src/Cmixin/HolidayNames/nl.php new file mode 100644 index 0000000..3818ed0 --- /dev/null +++ b/src/Cmixin/HolidayNames/nl.php @@ -0,0 +1,32 @@ + 'Wapenstilstand 1918', + 'ascension' => 'Hemelvaart', + 'assumption' => 'Veronderstelling', + 'christmas' => 'Eerste Kerstdag', + 'christmas-next-day' => 'Tweede Kerstdag', + 'easter' => 'Paaszondag', + 'easter-monday' => 'Paasmaandag', + 'epiphany' => 'Driekoningen', + 'good-friday' => 'Goede Vrijdag', + 'independence-day' => 'Onafhankelijkheidsdag', + 'labor-day' => 'Dag van de Arbeid', + 'liberation-day' => 'Bevrijdingsdag', + 'memorial-day' => 'Herdenkingsdag', + 'mlk-day' => 'Martin Luther King Jr. Day', + 'national-day' => 'Nationale Dag', + 'new-year' => 'Nieuwjaarsdag', + 'new-year-next-day' => 'Nieuw jaar de volgende dag', + 'pentecost' => 'Pinksterzondag', + 'pentecost-monday' => 'Pinkstermaandag', + 'preseren-day' => 'Prešeren Dag', + 'rebellion-day' => 'Rebelliedag', + 'reformation-day' => 'Reformatie Dag', + 'royal-day' => 'Koningsdag', + 'thanksgiving' => 'Dankzegging', + 'toussaint' => 'Toussaint', + 'vacation-day' => 'Vakantiedag', + 'vacation-next-day' => 'Vakantiedag volgende dag', + 'victory-1945' => 'Overwinning 1945', +); diff --git a/src/Cmixin/HolidayNames/sl.php b/src/Cmixin/HolidayNames/sl.php new file mode 100644 index 0000000..211ad83 --- /dev/null +++ b/src/Cmixin/HolidayNames/sl.php @@ -0,0 +1,32 @@ + 'Premirje 1918', + 'ascension' => 'Vzpon', + 'assumption' => 'Marijino vnebovzetje', + 'christmas' => 'Božič', + 'christmas-next-day' => 'Božič naslednji dan', + 'easter' => 'Velika noč', + 'easter-monday' => 'Velikonočni ponedeljek', + 'epiphany' => 'Razodetje', + 'good-friday' => 'Dober petek', + 'independence-day' => 'Dan samostojnosti in enotnosti', + 'labor-day' => 'Dan dela', + 'liberation-day' => 'Dan osvoboditve', + 'memorial-day' => 'Dan spomina na mrtve', + 'mlk-day' => 'Martin Luther King mlajši dan', + 'national-day' => 'Dan državnosti', + 'new-year' => 'Novo leto', + 'new-year-next-day' => 'Novo leto naslednji dan', + 'pentecost' => 'Binkoštna nedelja', + 'pentecost-monday' => 'Binkoštna ponedeljek', + 'preseren-day' => 'Prešernov dan', + 'rebellion-day' => 'Dan upora proti okupatorju', + 'reformation-day' => 'Dan reformacije', + 'royal-day' => 'Kraljevi dan', + 'thanksgiving' => 'Dan zahvalnosti', + 'toussaint' => 'Toussaint', + 'vacation-day' => 'Praznik dela', + 'vacation-next-day' => 'Praznik dela naslednji dan', + 'victory-1945' => 'Zmaga 1945', +); diff --git a/src/Cmixin/Holidays/fr-national.php b/src/Cmixin/Holidays/fr-national.php index b9ef52f..466d323 100644 --- a/src/Cmixin/Holidays/fr-national.php +++ b/src/Cmixin/Holidays/fr-national.php @@ -10,8 +10,8 @@ return $date->format('d/m'); }, - 'labor-day' => '01/05', // Fête du travail - 'victory-day' => '08/05', // Victoire 1945 + 'labor-day' => '01/05', // Fête du travail + 'victory-1945' => '08/05', // Victoire 1945 // Ascension 'ascension' => function ($year) { $days = easter_days($year) + 39; @@ -26,9 +26,9 @@ return $date->format('d/m'); }, - 'national-day' => '14/07', // Fête nationale - 'assumption' => '15/08', // Assomption - 'toussaint' => '01/11', // Toussaint - 'armistice' => '11/11', // Armistice 1918 - 'christmas' => '25/12', // Noël + 'national-day' => '14/07', // Fête nationale + 'assumption' => '15/08', // Assomption + 'toussaint' => '01/11', // Toussaint + 'armistice-1918' => '11/11', // Armistice 1918 + 'christmas' => '25/12', // Noël ); diff --git a/src/Cmixin/Holidays/nl-national.php b/src/Cmixin/Holidays/nl-national.php index da53bff..7fc4e19 100644 --- a/src/Cmixin/Holidays/nl-national.php +++ b/src/Cmixin/Holidays/nl-national.php @@ -41,14 +41,14 @@ return $date->format('d/m'); }, // Pinksterzondag - 'pentcost' => function ($year) { + 'pentecost' => function ($year) { $days = easter_days($year) + 49; $date = new DateTime("$year-03-21 +$days days"); return $date->format('d/m'); }, // Pinkstermaandag - 'pentcost-monday' => function ($year) { + 'pentecost-monday' => function ($year) { $days = easter_days($year) + 50; $date = new DateTime("$year-03-21 +$days days"); diff --git a/tests/Cmixin/BusinessDayTest.php b/tests/Cmixin/BusinessDayTest.php index 9284ebe..e3f3a78 100644 --- a/tests/Cmixin/BusinessDayTest.php +++ b/tests/Cmixin/BusinessDayTest.php @@ -527,6 +527,43 @@ public function testObserveHolidays() self::assertFalse($carbon::parse('2018-12-26')->isObservedHoliday()); } + public function testGetHolidayName() + { + $carbon = static::CARBON_CLASS; + $carbon::setLocale('en'); + $carbon::setHolidaysRegion('fr-national'); + $carbon::setTestNow('2018-12-25'); + self::assertSame('en', $carbon::getLocale()); + self::assertSame('Christmas', $carbon::getHolidayName()); + self::assertSame('National Day', $carbon::getHolidayName(new \DateTime('2018-07-14'))); + self::assertSame('Noël', $carbon::getHolidayName('fr')); + $carbon::setTestNow('2018-12-26'); + self::assertFalse($carbon::getHolidayName()); + self::assertSame('New Year', $carbon::parse('2018-01-01')->getHolidayName()); + self::assertSame('Novo leto', $carbon::parse('2018-01-01')->getHolidayName('sl_SI')); + $carbon::setLocale('nl'); + self::assertSame('nl', $carbon::getLocale()); + self::assertSame('Nieuwjaarsdag', $carbon::parse('2018-01-01')->getHolidayName()); + $carbon::setLocale('de'); // Language not translated + self::assertSame('de', $carbon::getLocale()); + self::assertSame('New Year', $carbon::parse('2018-01-01')->getHolidayName()); + } + + public function testGetHolidayNameLocalLocale() + { + $carbon = static::CARBON_CLASS; + $carbon::setLocale('en'); + $carbon::setHolidaysRegion('fr-national'); + $date = $carbon::parse('2018-01-01'); + + if (!method_exists($date, 'locale')) { + self::markTestSkipped('Test for Carbon 2 only.'); + } + + self::assertSame('New Year', $date->getHolidayName()); + self::assertSame('Nouvel an', $date->locale('fr')->getHolidayName()); + } + /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage You must pass holiday names as a string or "all".