From f2dd574bf329aa6e610dac2b62c4a1743e9a4fa2 Mon Sep 17 00:00:00 2001 From: Florian Heinrich Date: Tue, 21 Jan 2020 13:20:41 +0100 Subject: [PATCH 1/6] update ukraine holidays --- src/Yasumi/Holiday.php | 6 +- src/Yasumi/Provider/Ukraine.php | 136 +++++++++++--- ...yTest.php => CatholicChristmasDayTest.php} | 14 +- tests/Ukraine/PostponedHolidayTest.php | 177 ++++++++++++++++++ tests/Ukraine/UkraineTest.php | 6 +- 5 files changed, 308 insertions(+), 31 deletions(-) rename tests/Ukraine/{SecondInternationalWorkersDayTest.php => CatholicChristmasDayTest.php} (82%) create mode 100644 tests/Ukraine/PostponedHolidayTest.php diff --git a/src/Yasumi/Holiday.php b/src/Yasumi/Holiday.php index 9a185db50..5de7c25ab 100755 --- a/src/Yasumi/Holiday.php +++ b/src/Yasumi/Holiday.php @@ -1,4 +1,6 @@ -timezone = 'Europe/Kiev'; // Add common holidays - $this->addHoliday($this->newYearsDay($this->year, $this->timezone, $this->locale)); + // New Years Day will not be postponed to an monday if it's on a weekend! + $this->addHoliday($this->newYearsDay($this->year, $this->timezone, $this->locale), false); $this->addHoliday($this->internationalWorkersDay($this->year, $this->timezone, $this->locale)); $this->addHoliday($this->internationalWomensDay($this->year, $this->timezone, $this->locale)); @@ -58,11 +69,85 @@ public function initialize(): void // Add other holidays $this->calculateChristmasDay(); - $this->calculateSecondInternationalWorkersDay(); $this->calculateVictoryDay(); $this->calculateConstitutionDay(); $this->calculateIndependenceDay(); $this->calculateDefenderOfUkraineDay(); + $this->calculateCatholicChristmasDay(); + } + + /** + * Adds a holiday to the holidays providers (i.e. country/state) list of holidays. + * + * @param Holiday $holiday Holiday instance (representing a holiday) to be added to the internal list + * of holidays of this country. + * @param bool $postpone Holidays on a weekend will be postponed to the next monday. + * @param bool $addOnlyPostpone If $postpone is true add holidays on a weekend on the postponed day. + */ + public function addHoliday(Holiday $holiday, bool $postpone = true, bool $addOnlyPostpone = false): void + { + if (!$postpone || !$this->isWeekendDay($holiday)) { + parent::addHoliday($holiday); + return; + } + + // Special case: Holiday on a weekend and should be postpone to monday. + + // Add original holiday. + if (!$addOnlyPostpone) { + parent::addHoliday($holiday); + } + + // Create postponed holiday. + $postponed = new Holiday( + $holiday->shortName . 'Postponed', + $holiday->translations, + $holiday, + $holiday->displayLocale, + self::TYPE_POSTPONED + ); + + // Holidays on weekends will be postponed to monday. + do { + $postponed->modify('+1 days'); + } while ($this->isWeekendDay($postponed)); + + // Create add holiday. + parent::addHoliday($postponed); + } + + /** + * Returns the number of defined holidays (for the given country and the given year). + * In case a holiday is substituted (e.g. observed), the holiday is only counted once. + * + * @param bool $ignorePostponedHolidays Do not count postponed holidays. + * + * @return int number of holidays + */ + public function count(bool $ignorePostponedHolidays = true): int + { + $names = \array_reduce( + $this->getHolidays(), + static function (&$carry, &$holiday) use (&$ignorePostponedHolidays) { + // Ignore postponed holidays. + if ($ignorePostponedHolidays) { + if ($holiday->getType() == self::TYPE_POSTPONED) { + return $carry; + } + } + + if ($holiday instanceof SubstituteHoliday) { + $carry[] = $holiday->substitutedHoliday->shortName; + return $carry; + } + + $carry[] = $holiday->shortName; + return $carry; + }, + [] + ); + + return \count(\array_unique($names)); } /** @@ -83,24 +168,6 @@ private function calculateChristmasDay(): void )); } - /** - * International Workers' Day. - * - * @link https://en.wikipedia.org/wiki/International_Workers%27_Day#Ukraine - * - * @throws InvalidDateException - * @throws \InvalidArgumentException - * @throws UnknownLocaleException - * @throws \Exception - */ - private function calculateSecondInternationalWorkersDay(): void - { - $this->addHoliday(new Holiday('secondInternationalWorkersDay', [ - 'uk' => 'День міжнародної солідарності трудящих', - 'ru' => 'День международной солидарности трудящихся', - ], new \DateTime("$this->year-05-02", new \DateTimeZone($this->timezone)), $this->locale)); - } - /** * Victory Day over Nazism in World War II * @@ -222,4 +289,31 @@ public function calculateEaster(int $year, string $timezone): \DateTime { return $this->calculateOrthodoxEaster($year, $timezone); } + + /** + * Catholic Christmas Day. + * (since 2017 instead of International Workers' Day 2. May) + * + * @link https://en.wikipedia.org/wiki/Christmas_in_Ukraine + * + * @throws InvalidDateException + * @throws \InvalidArgumentException + * @throws UnknownLocaleException + * @throws \Exception + */ + private function calculateCatholicChristmasDay(): void + { + $this->addHoliday( + new Holiday( + 'catholicChristmasDay', + [ + 'uk' => 'Католицький день Різдва', + 'ru' => 'Католическое рождество', + ], + new \DateTime("$this->year-12-25", new \DateTimeZone($this->timezone)), + $this->locale + ), + false // Catholic Christmas Day will not be postponed to an monday if it's on a weekend! + ); + } } diff --git a/tests/Ukraine/SecondInternationalWorkersDayTest.php b/tests/Ukraine/CatholicChristmasDayTest.php similarity index 82% rename from tests/Ukraine/SecondInternationalWorkersDayTest.php rename to tests/Ukraine/CatholicChristmasDayTest.php index 10c6fb859..03aada0bd 100644 --- a/tests/Ukraine/SecondInternationalWorkersDayTest.php +++ b/tests/Ukraine/CatholicChristmasDayTest.php @@ -1,4 +1,6 @@ -generateRandomYear(), - [self::LOCALE => 'День міжнародної солідарності трудящих'] + [self::LOCALE => 'Католицький день Різдва'] ); } @@ -75,6 +77,6 @@ public function testHolidayType(): void */ public function SecondInternationalWorkersDayDataProvider(): array { - return $this->generateRandomDates(5, 2, self::TIMEZONE); + return $this->generateRandomDates(12, 25, self::TIMEZONE); } } diff --git a/tests/Ukraine/PostponedHolidayTest.php b/tests/Ukraine/PostponedHolidayTest.php new file mode 100644 index 000000000..8bd558c7f --- /dev/null +++ b/tests/Ukraine/PostponedHolidayTest.php @@ -0,0 +1,177 @@ + + */ + +namespace Yasumi\tests\Ukraine; + +use DateTime; +use DateTimeZone; +use Exception; +use ReflectionException; +use Yasumi\Holiday; +use Yasumi\Provider\Ukraine; +use Yasumi\tests\YasumiTestCaseInterface; +use Yasumi\Yasumi; + +/** + * Class PostponedHolidayTest + * @package Yasumi\tests\Ukraine + */ +class PostponedHolidayTest extends UkraineBaseTestCase implements YasumiTestCaseInterface +{ + /** + * Tests the postponement of holidays on saturday (weekend). + * @throws Exception + * @throws ReflectionException + */ + public function testSaturdayPostponement() + { + // 2020-05-09 victoryDay (День перемоги) + $year = 2020; + $holiday = 'victoryDay'; + + $this->assertHolidayWithPostponement( + self::REGION, + $holiday, + $year, + new DateTime("$year-05-09", new DateTimeZone(self::TIMEZONE)), + new DateTime("$year-05-11", new DateTimeZone(self::TIMEZONE)) + ); + } + + /** + * Tests the postponement of holidays on sunday (weekend). + * @throws Exception + * @throws ReflectionException + */ + public function testSundayPostponement(): void + { + // 2020-06-28 constitutionDay (День Конституції) + $year = 2020; + $holiday = 'constitutionDay'; + + $this->assertHolidayWithPostponement( + self::REGION, + $holiday, + $year, + new DateTime("$year-06-28", new DateTimeZone(self::TIMEZONE)), + new DateTime("$year-06-29", new DateTimeZone(self::TIMEZONE)) + ); + } + + /** + * Tests the postponement of new year (1. January) on a weekend. + * Special: no postponement at new year (1. January) on a weekend. + * @throws Exception + * @throws ReflectionException + */ + public function testNewYearNoPostponement(): void + { + // 2022-01-01 (Saturday) constitutionDay (Новий Рік) + $year = 2022; + $holiday = 'newYearsDay'; + + $this->assertHolidayWithPostponement( + self::REGION, + $holiday, + $year, + new DateTime("$year-01-01", new DateTimeZone(self::TIMEZONE)) + ); + } + + /** + * Tests the postponement of Catholic Christmas Day (25. December) on a weekend. + * Special: no postponement at Catholic Christmas Day (25. December) on a weekend. + * @throws Exception + * @throws ReflectionException + */ + public function testCatholicChristmasDayNoPostponement(): void + { + // 2022-12-25 (Sunday) catholicChristmasDay (Католицький день Різдва) + $year = 2022; + $holiday = 'catholicChristmasDay'; + + $this->assertHolidayWithPostponement( + self::REGION, + $holiday, + $year, + new DateTime("$year-12-25", new DateTimeZone(self::TIMEZONE)) + ); + } + + /** + * Dummy: Tests the translated name of the holiday defined in this test. + * @throws ReflectionException + */ + public function testTranslation(): void + { + $this->assertTrue(true); + } + + /** + * Dummy: Tests type of the holiday defined in this test. + * @throws ReflectionException + */ + public function testHolidayType(): void + { + $this->assertTrue(true); + } + + /** + * Asserts that the expected date is indeed a holiday for that given year and name + * + * @param string $provider the holiday provider (i.e. country/state) for which the holiday need to be tested + * @param string $shortName string the short name of the holiday to be checked against + * @param int $year holiday calendar year + * @param DateTime $expected the official date to be checked against + * @param DateTime $expected the postponed date to be checked against + * + * @throws UnknownLocaleException + * @throws InvalidDateException + * @throws InvalidArgumentException + * @throws RuntimeException + * @throws AssertionFailedError + * @throws ReflectionException + */ + public function assertHolidayWithPostponement( + string $provider, + string $shortName, + int $year, + DateTime $expectedOfficial, + DateTime $expectedPostponed = null + ): void { + $holidays = Yasumi::create($provider, $year); + + $holidayOfficial = $holidays->getHoliday($shortName); + $this->assertInstanceOf(Holiday::class, $holidayOfficial); + $this->assertNotNull($holidayOfficial); + $this->assertEquals($expectedOfficial, $holidayOfficial); + $this->assertTrue($holidays->isHoliday($holidayOfficial)); + $this->assertEquals(Holiday::TYPE_OFFICIAL, $holidayOfficial->getType()); + + $holidayPostponed = $holidays->getHoliday($shortName . 'Postponed'); + if ($expectedPostponed === null) { + // without postponement + $this->assertNull($holidayPostponed); + } else { + // with postponement + $this->assertInstanceOf(Holiday::class, $holidayPostponed); + $this->assertNotNull($holidayPostponed); + $this->assertEquals($expectedPostponed, $holidayPostponed); + $this->assertTrue($holidays->isHoliday($holidayPostponed)); + $this->assertEquals(Ukraine::TYPE_POSTPONED, $holidayPostponed->getType()); + } + + unset($holidayOfficial, $holidayPostponed, $holidays); + } +} diff --git a/tests/Ukraine/UkraineTest.php b/tests/Ukraine/UkraineTest.php index 6ceb4a95f..f4d6ceeb2 100644 --- a/tests/Ukraine/UkraineTest.php +++ b/tests/Ukraine/UkraineTest.php @@ -1,4 +1,6 @@ -assertDefinedHolidays([ 'newYearsDay', 'internationalWorkersDay', - 'secondInternationalWorkersDay', 'christmasDay', 'easter', 'pentecost', @@ -44,6 +45,7 @@ public function testOfficialHolidays(): void 'constitutionDay', 'independenceDay', 'defenderOfUkraineDay', + 'catholicChristmasDay', ], self::REGION, $this->year, Holiday::TYPE_OFFICIAL); } From e3d9e300c37313f1e5073540c7ccece54bf6435d Mon Sep 17 00:00:00 2001 From: Florian Heinrich Date: Tue, 28 Jan 2020 18:16:03 +0100 Subject: [PATCH 2/6] apply recommendations --- src/Yasumi/Holiday.php | 5 +- src/Yasumi/Provider/Ukraine.php | 120 +++++++----------- tests/Base/WeekendTest.php | 3 +- tests/Ukraine/CatholicChristmasDayTest.php | 44 +++++-- .../SecondInternationalWorkersDayTest.php | 108 ++++++++++++++++ ...dayTest.php => SubstitutedHolidayTest.php} | 73 ++++++----- tests/Ukraine/UkraineTest.php | 3 +- 7 files changed, 232 insertions(+), 124 deletions(-) create mode 100644 tests/Ukraine/SecondInternationalWorkersDayTest.php rename tests/Ukraine/{PostponedHolidayTest.php => SubstitutedHolidayTest.php} (66%) diff --git a/src/Yasumi/Holiday.php b/src/Yasumi/Holiday.php index 5de7c25ab..55841b65a 100755 --- a/src/Yasumi/Holiday.php +++ b/src/Yasumi/Holiday.php @@ -1,6 +1,5 @@ -timezone = 'Europe/Kiev'; // Add common holidays - // New Years Day will not be postponed to an monday if it's on a weekend! + // New Years Day will not be substituted to an monday if it's on a weekend! $this->addHoliday($this->newYearsDay($this->year, $this->timezone, $this->locale), false); $this->addHoliday($this->internationalWorkersDay($this->year, $this->timezone, $this->locale)); $this->addHoliday($this->internationalWomensDay($this->year, $this->timezone, $this->locale)); @@ -69,6 +61,7 @@ public function initialize(): void // Add other holidays $this->calculateChristmasDay(); + $this->calculateSecondInternationalWorkersDay(); $this->calculateVictoryDay(); $this->calculateConstitutionDay(); $this->calculateIndependenceDay(); @@ -81,73 +74,27 @@ public function initialize(): void * * @param Holiday $holiday Holiday instance (representing a holiday) to be added to the internal list * of holidays of this country. - * @param bool $postpone Holidays on a weekend will be postponed to the next monday. - * @param bool $addOnlyPostpone If $postpone is true add holidays on a weekend on the postponed day. - */ - public function addHoliday(Holiday $holiday, bool $postpone = true, bool $addOnlyPostpone = false): void - { - if (!$postpone || !$this->isWeekendDay($holiday)) { - parent::addHoliday($holiday); - return; - } - - // Special case: Holiday on a weekend and should be postpone to monday. - - // Add original holiday. - if (!$addOnlyPostpone) { - parent::addHoliday($holiday); - } - - // Create postponed holiday. - $postponed = new Holiday( - $holiday->shortName . 'Postponed', - $holiday->translations, - $holiday, - $holiday->displayLocale, - self::TYPE_POSTPONED - ); - - // Holidays on weekends will be postponed to monday. - do { - $postponed->modify('+1 days'); - } while ($this->isWeekendDay($postponed)); - - // Create add holiday. - parent::addHoliday($postponed); - } - - /** - * Returns the number of defined holidays (for the given country and the given year). - * In case a holiday is substituted (e.g. observed), the holiday is only counted once. - * - * @param bool $ignorePostponedHolidays Do not count postponed holidays. - * - * @return int number of holidays + * @param bool $substitutable Holidays on a weekend will be substituted to the next monday. */ - public function count(bool $ignorePostponedHolidays = true): int + public function addHoliday(Holiday $holiday, bool $substitutable = true): void { - $names = \array_reduce( - $this->getHolidays(), - static function (&$carry, &$holiday) use (&$ignorePostponedHolidays) { - // Ignore postponed holidays. - if ($ignorePostponedHolidays) { - if ($holiday->getType() == self::TYPE_POSTPONED) { - return $carry; - } - } + parent::addHoliday($holiday); - if ($holiday instanceof SubstituteHoliday) { - $carry[] = $holiday->substitutedHoliday->shortName; - return $carry; - } + if (!$substitutable) return; - $carry[] = $holiday->shortName; - return $carry; - }, - [] - ); + // Substitute holiday is on the next available weekday + // if a holiday falls on a Saturday or Sunday. + if ($this->isWeekendDay($holiday)) { + $date = clone $holiday; + $date->modify('next monday'); - return \count(\array_unique($names)); + parent::addHoliday(new SubstituteHoliday( + $holiday, + [], + $date, + $this->locale + )); + } } /** @@ -168,6 +115,29 @@ private function calculateChristmasDay(): void )); } + /** + * International Workers' Day. + * National holiday until 2018. + * + * @link https://en.wikipedia.org/wiki/International_Workers%27_Day#Ukraine + * + * @throws InvalidDateException + * @throws \InvalidArgumentException + * @throws UnknownLocaleException + * @throws \Exception + */ + private function calculateSecondInternationalWorkersDay(): void + { + if ($this->year >= 2018) { + return; + } + + $this->addHoliday(new Holiday('secondInternationalWorkersDay', [ + 'uk' => 'День міжнародної солідарності трудящих', + 'ru' => 'День международной солидарности трудящихся', + ], new \DateTime("$this->year-05-02", new \DateTimeZone($this->timezone)), $this->locale)); + } + /** * Victory Day over Nazism in World War II * @@ -303,6 +273,10 @@ public function calculateEaster(int $year, string $timezone): \DateTime */ private function calculateCatholicChristmasDay(): void { + if ($this->year < 2017) { + return; + } + $this->addHoliday( new Holiday( 'catholicChristmasDay', @@ -313,7 +287,7 @@ private function calculateCatholicChristmasDay(): void new \DateTime("$this->year-12-25", new \DateTimeZone($this->timezone)), $this->locale ), - false // Catholic Christmas Day will not be postponed to an monday if it's on a weekend! + false // Catholic Christmas Day will not be substituted to an monday if it's on a weekend! ); } } diff --git a/tests/Base/WeekendTest.php b/tests/Base/WeekendTest.php index 1185d6df2..ef4c3cfbc 100644 --- a/tests/Base/WeekendTest.php +++ b/tests/Base/WeekendTest.php @@ -1,5 +1,4 @@ -assertHoliday(self::REGION, self::HOLIDAY, $year, $expected); } + /** + * Tests Catholic Christmas Day before 2017. + * @throws ReflectionException + */ + public function testNoCatholicChristmasDayBefore2017() + { + $year = $this->generateRandomYear(null, 2016); + $holidays = Yasumi::create(self::REGION, $year); + $holiday = $holidays->getHoliday(self::HOLIDAY); + + $this->assertNull($holiday); + + unset($year, $holiday, $holidays); + } + /** * Tests translated name of the holiday defined in this test. * @throws ReflectionException @@ -55,7 +70,7 @@ public function testTranslation(): void $this->assertTranslatedHolidayName( self::REGION, self::HOLIDAY, - $this->generateRandomYear(), + $this->generateRandomYear(2017), [self::LOCALE => 'Католицький день Різдва'] ); } @@ -66,17 +81,24 @@ public function testTranslation(): void */ public function testHolidayType(): void { - $this->assertHolidayType(self::REGION, self::HOLIDAY, $this->generateRandomYear(), Holiday::TYPE_OFFICIAL); + $this->assertHolidayType(self::REGION, self::HOLIDAY, $this->generateRandomYear(2017), Holiday::TYPE_OFFICIAL); } /** - * Returns a list of random test dates used for assertion of International Workers' Day. + * Returns a list of random test dates used for assertion of Catholic Christmas Day. * - * @return array list of test dates for International Workers' Day + * @return array list of test dates for Catholic Christmas Day * @throws Exception */ - public function SecondInternationalWorkersDayDataProvider(): array + public function CatholicChristmasDayDataProvider(): array { - return $this->generateRandomDates(12, 25, self::TIMEZONE); + $data = []; + + for ($y = 0; $y < 10; $y++) { + $year = $this->generateRandomYear(2017); + $data[] = [$year, new \DateTime("$year-12-25", new \DateTimeZone(self::TIMEZONE))]; + } + + return $data; } } diff --git a/tests/Ukraine/SecondInternationalWorkersDayTest.php b/tests/Ukraine/SecondInternationalWorkersDayTest.php new file mode 100644 index 000000000..9fff35ba3 --- /dev/null +++ b/tests/Ukraine/SecondInternationalWorkersDayTest.php @@ -0,0 +1,108 @@ + + */ + +namespace Yasumi\tests\Ukraine; + +use DateTime; +use ReflectionException; +use Yasumi\Holiday; +use Yasumi\tests\YasumiTestCaseInterface; +use Yasumi\Yasumi; + +/** + * Class SecondInternationalWorkersDayTest + * @package Yasumi\tests\Ukraine + */ +class SecondInternationalWorkersDayTest extends UkraineBaseTestCase implements YasumiTestCaseInterface +{ + /** + * The name of the holiday + */ + public const HOLIDAY = 'secondInternationalWorkersDay'; + + /** + * Tests International Workers' Day. + * + * @dataProvider SecondInternationalWorkersDayDataProvider + * + * @param int $year the year for which International Workers' Day needs to be tested + * @param DateTime $expected the expected date + * + * @throws ReflectionException + */ + public function testSecondInternationalWorkersDay($year, $expected) + { + $this->assertHoliday(self::REGION, self::HOLIDAY, $year, $expected); + } + + /** + * Tests International Workers' Day since 2018. + * @throws ReflectionException + */ + public function testNoSecondInternationalWorkersDaySince2018() + { + $year = $this->generateRandomYear(2018); + $holidays = Yasumi::create(self::REGION, $year); + $holiday = $holidays->getHoliday(self::HOLIDAY); + + $this->assertNull($holiday); + + unset($year, $holiday, $holidays); + } + + /** + * Tests translated name of the holiday defined in this test. + * @throws ReflectionException + */ + public function testTranslation(): void + { + $this->assertTranslatedHolidayName( + self::REGION, + self::HOLIDAY, + $this->generateRandomYear(null, 2017), + [self::LOCALE => 'День міжнародної солідарності трудящих'] + ); + } + + /** + * Tests type of the holiday defined in this test. + * @throws ReflectionException + */ + public function testHolidayType(): void + { + $this->assertHolidayType( + self::REGION, + self::HOLIDAY, + $this->generateRandomYear(null, 2017), + Holiday::TYPE_OFFICIAL + ); + } + + /** + * Returns a list of random test dates used for assertion of International Workers' Day. + * + * @return array list of test dates for International Workers' Day + * @throws Exception + */ + public function SecondInternationalWorkersDayDataProvider(): array + { + $data = []; + + for ($y = 0; $y < 10; $y++) { + $year = $this->generateRandomYear(null, 2017); + $data[] = [$year, new \DateTime("$year-05-02", new \DateTimeZone(self::TIMEZONE))]; + } + + return $data; + } +} diff --git a/tests/Ukraine/PostponedHolidayTest.php b/tests/Ukraine/SubstitutedHolidayTest.php similarity index 66% rename from tests/Ukraine/PostponedHolidayTest.php rename to tests/Ukraine/SubstitutedHolidayTest.php index 8bd558c7f..b8e8db952 100644 --- a/tests/Ukraine/PostponedHolidayTest.php +++ b/tests/Ukraine/SubstitutedHolidayTest.php @@ -1,6 +1,5 @@ -assertHolidayWithPostponement( + $this->assertHolidayWithSubstitution( self::REGION, $holiday, $year, new DateTime("$year-05-09", new DateTimeZone(self::TIMEZONE)), new DateTime("$year-05-11", new DateTimeZone(self::TIMEZONE)) ); + + unset($year, $holiday); } /** - * Tests the postponement of holidays on sunday (weekend). + * Tests the substitution of holidays on sunday (weekend). * @throws Exception * @throws ReflectionException */ - public function testSundayPostponement(): void + public function testSundaySubstitution(): void { // 2020-06-28 constitutionDay (День Конституції) $year = 2020; $holiday = 'constitutionDay'; - $this->assertHolidayWithPostponement( + $this->assertHolidayWithSubstitution( self::REGION, $holiday, $year, new DateTime("$year-06-28", new DateTimeZone(self::TIMEZONE)), new DateTime("$year-06-29", new DateTimeZone(self::TIMEZONE)) ); + + unset($year, $holiday); } /** - * Tests the postponement of new year (1. January) on a weekend. - * Special: no postponement at new year (1. January) on a weekend. + * Tests the substitution of new year (1. January) on a weekend. + * Special: no substitution at new year (1. January) on a weekend. * @throws Exception * @throws ReflectionException */ - public function testNewYearNoPostponement(): void + public function testNewYearNoSubstitution(): void { // 2022-01-01 (Saturday) constitutionDay (Новий Рік) $year = 2022; $holiday = 'newYearsDay'; - $this->assertHolidayWithPostponement( + $this->assertHolidayWithSubstitution( self::REGION, $holiday, $year, new DateTime("$year-01-01", new DateTimeZone(self::TIMEZONE)) ); + + unset($year, $holiday); } /** - * Tests the postponement of Catholic Christmas Day (25. December) on a weekend. - * Special: no postponement at Catholic Christmas Day (25. December) on a weekend. + * Tests the substitution of Catholic Christmas Day (25. December) on a weekend. + * Special: no substitution at Catholic Christmas Day (25. December) on a weekend. * @throws Exception * @throws ReflectionException */ - public function testCatholicChristmasDayNoPostponement(): void + public function testCatholicChristmasDayNoSubstitution(): void { // 2022-12-25 (Sunday) catholicChristmasDay (Католицький день Різдва) $year = 2022; $holiday = 'catholicChristmasDay'; - $this->assertHolidayWithPostponement( + $this->assertHolidayWithSubstitution( self::REGION, $holiday, $year, new DateTime("$year-12-25", new DateTimeZone(self::TIMEZONE)) ); + + unset($year, $holiday); } /** @@ -134,7 +141,7 @@ public function testHolidayType(): void * @param string $shortName string the short name of the holiday to be checked against * @param int $year holiday calendar year * @param DateTime $expected the official date to be checked against - * @param DateTime $expected the postponed date to be checked against + * @param DateTime $expected the substituted date to be checked against * * @throws UnknownLocaleException * @throws InvalidDateException @@ -143,12 +150,12 @@ public function testHolidayType(): void * @throws AssertionFailedError * @throws ReflectionException */ - public function assertHolidayWithPostponement( + public function assertHolidayWithSubstitution( string $provider, string $shortName, int $year, DateTime $expectedOfficial, - DateTime $expectedPostponed = null + DateTime $expectedSubstitution = null ): void { $holidays = Yasumi::create($provider, $year); @@ -159,19 +166,19 @@ public function assertHolidayWithPostponement( $this->assertTrue($holidays->isHoliday($holidayOfficial)); $this->assertEquals(Holiday::TYPE_OFFICIAL, $holidayOfficial->getType()); - $holidayPostponed = $holidays->getHoliday($shortName . 'Postponed'); - if ($expectedPostponed === null) { - // without postponement - $this->assertNull($holidayPostponed); + $holidaySubstitution = $holidays->getHoliday('substituteHoliday:' . $holidayOfficial->shortName); + if ($expectedSubstitution === null) { + // without substitution + $this->assertNull($holidaySubstitution); } else { - // with postponement - $this->assertInstanceOf(Holiday::class, $holidayPostponed); - $this->assertNotNull($holidayPostponed); - $this->assertEquals($expectedPostponed, $holidayPostponed); - $this->assertTrue($holidays->isHoliday($holidayPostponed)); - $this->assertEquals(Ukraine::TYPE_POSTPONED, $holidayPostponed->getType()); + // with substitution + $this->assertNotNull($holidaySubstitution); + $this->assertInstanceOf(SubstituteHoliday::class, $holidaySubstitution); + $this->assertEquals($expectedSubstitution, $holidaySubstitution); + $this->assertTrue($holidays->isHoliday($holidaySubstitution)); + $this->assertEquals(Holiday::TYPE_OFFICIAL, $holidaySubstitution->getType()); } - unset($holidayOfficial, $holidayPostponed, $holidays); + unset($holidayOfficial, $holidaySubstitution, $holidays); } } diff --git a/tests/Ukraine/UkraineTest.php b/tests/Ukraine/UkraineTest.php index f4d6ceeb2..3312dfff6 100644 --- a/tests/Ukraine/UkraineTest.php +++ b/tests/Ukraine/UkraineTest.php @@ -1,6 +1,5 @@ - Date: Tue, 28 Jan 2020 18:26:12 +0100 Subject: [PATCH 3/6] fix style ci error --- src/Yasumi/Provider/Ukraine.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Yasumi/Provider/Ukraine.php b/src/Yasumi/Provider/Ukraine.php index 662f02abf..a45a8f29f 100644 --- a/src/Yasumi/Provider/Ukraine.php +++ b/src/Yasumi/Provider/Ukraine.php @@ -80,7 +80,9 @@ public function addHoliday(Holiday $holiday, bool $substitutable = true): void { parent::addHoliday($holiday); - if (!$substitutable) return; + if (!$substitutable) { + return; + } // Substitute holiday is on the next available weekday // if a holiday falls on a Saturday or Sunday. From 18d610790b054b2f25f525eb211f86a6decfc006 Mon Sep 17 00:00:00 2001 From: Florian Heinrich Date: Tue, 28 Jan 2020 18:40:35 +0100 Subject: [PATCH 4/6] fix test date (year) range --- tests/Ukraine/UkraineTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Ukraine/UkraineTest.php b/tests/Ukraine/UkraineTest.php index 3312dfff6..b6cf1cc55 100644 --- a/tests/Ukraine/UkraineTest.php +++ b/tests/Ukraine/UkraineTest.php @@ -36,6 +36,7 @@ public function testOfficialHolidays(): void $this->assertDefinedHolidays([ 'newYearsDay', 'internationalWorkersDay', + //'secondInternationalWorkersDay', // until 2018 'christmasDay', 'easter', 'pentecost', @@ -89,6 +90,6 @@ public function testOtherHolidays(): void */ protected function setUp(): void { - $this->year = $this->generateRandomYear(2015, 2025); + $this->year = $this->generateRandomYear(2017, 2025); } } From 9746969016b9a6072845467073c2f7469c3de0fb Mon Sep 17 00:00:00 2001 From: Florian Heinrich Date: Mon, 3 Feb 2020 16:56:32 +0100 Subject: [PATCH 5/6] apply recommendations --- CHANGELOG.md | 3 +++ src/Yasumi/Provider/Ukraine.php | 5 +++++ tests/Ukraine/UkraineTest.php | 38 ++++++++++++++++++++++++++------- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81bdb306a..dffa5eaea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/) and this - Holiday providers for states of Austria. [\#182](https://github.com/azuyalabs/yasumi/pull/182) ([aprog](https://github.com/aprog)) - Added missing return (correct) and parameter types in various methods. - Day of Liberation (Tag der Befreiung) is an one-time official holiday in 2020 in Berlin (Germany). +- Catholic Christmas Day is a new official holiday since 2017 in the Ukraine. [\#202](https://github.com/azuyalabs/yasumi/pull/202) ### Changed - Holiday names in Danish, Dutch, and Norwegian are no longer capitalized. [\#185](https://github.com/azuyalabs/yasumi/pull/185) ([c960657](https://github.com/c960657)) @@ -21,12 +22,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/) and this - Refactored various conditional structures. - Changed signature of some methods as parameters with defaults should come after required parameters. - Updated third party dependencies. +- Second International Workers Day was an official holiday only until 2018. [\#202](https://github.com/azuyalabs/yasumi/pull/202) ### Fixed - Fixed issue if the next working day happens to be in the next year (i.e. not in the year of the Yasumi instance) [\#192](https://github.com/azuyalabs/yasumi/issues/192) ([tniemann](https://github.com/tniemann)) - Fixed issue if the previous working day happens to be in the previous year (i.e. not in the year of the Yasumi instance) - Fix locale fallback for substitute holidays [\#180](https://github.com/azuyalabs/yasumi/pull/180) ([c960657](https://github.com/c960657)) - Fixed compound conditions that are always true by simplifying the condition steps. +- Fixed Ukraine holidays on weekends. These days need to be substituted. [\#202](https://github.com/azuyalabs/yasumi/pull/202) ### Removed - PHP 7.1 Support, as it has reached its end of life. diff --git a/src/Yasumi/Provider/Ukraine.php b/src/Yasumi/Provider/Ukraine.php index a45a8f29f..b5ad4b90b 100644 --- a/src/Yasumi/Provider/Ukraine.php +++ b/src/Yasumi/Provider/Ukraine.php @@ -75,6 +75,11 @@ public function initialize(): void * @param Holiday $holiday Holiday instance (representing a holiday) to be added to the internal list * of holidays of this country. * @param bool $substitutable Holidays on a weekend will be substituted to the next monday. + * + * @throws InvalidDateException + * @throws UnknownLocaleException + * @throws \InvalidArgumentException + * @throws \Exception */ public function addHoliday(Holiday $holiday, bool $substitutable = true): void { diff --git a/tests/Ukraine/UkraineTest.php b/tests/Ukraine/UkraineTest.php index b6cf1cc55..959ffb919 100644 --- a/tests/Ukraine/UkraineTest.php +++ b/tests/Ukraine/UkraineTest.php @@ -33,20 +33,42 @@ class UkraineTest extends UkraineBaseTestCase */ public function testOfficialHolidays(): void { - $this->assertDefinedHolidays([ + $holidays = [ 'newYearsDay', 'internationalWorkersDay', - //'secondInternationalWorkersDay', // until 2018 'christmasDay', 'easter', 'pentecost', 'internationalWomensDay', 'victoryDay', - 'constitutionDay', - 'independenceDay', - 'defenderOfUkraineDay', - 'catholicChristmasDay', - ], self::REGION, $this->year, Holiday::TYPE_OFFICIAL); + ]; + + if ($this->year >= 1996) { + $holidays[] = 'constitutionDay'; + } + + if ($this->year >= 1991) { + $holidays[] = 'independenceDay'; + } + + if ($this->year >= 2015) { + $holidays[] = 'defenderOfUkraineDay'; + } + + if ($this->year < 2018) { + $holidays[] = 'secondInternationalWorkersDay'; + } + + if ($this->year >= 2017) { + $holidays[] = 'catholicChristmasDay'; + } + + $this->assertDefinedHolidays( + $holidays, + self::REGION, + $this->year, + Holiday::TYPE_OFFICIAL + ); } /** @@ -90,6 +112,6 @@ public function testOtherHolidays(): void */ protected function setUp(): void { - $this->year = $this->generateRandomYear(2017, 2025); + $this->year = $this->generateRandomYear(); } } From b356494dfa10a9c6094ff3743cf865f0754225d0 Mon Sep 17 00:00:00 2001 From: Florian Heinrich Date: Mon, 3 Feb 2020 17:05:29 +0100 Subject: [PATCH 6/6] fix styleci: remove tailing spaces --- src/Yasumi/Provider/Ukraine.php | 2 +- tests/Ukraine/UkraineTest.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Yasumi/Provider/Ukraine.php b/src/Yasumi/Provider/Ukraine.php index b5ad4b90b..61b5bd2b6 100644 --- a/src/Yasumi/Provider/Ukraine.php +++ b/src/Yasumi/Provider/Ukraine.php @@ -75,7 +75,7 @@ public function initialize(): void * @param Holiday $holiday Holiday instance (representing a holiday) to be added to the internal list * of holidays of this country. * @param bool $substitutable Holidays on a weekend will be substituted to the next monday. - * + * * @throws InvalidDateException * @throws UnknownLocaleException * @throws \InvalidArgumentException diff --git a/tests/Ukraine/UkraineTest.php b/tests/Ukraine/UkraineTest.php index 959ffb919..6c82c390e 100644 --- a/tests/Ukraine/UkraineTest.php +++ b/tests/Ukraine/UkraineTest.php @@ -64,9 +64,9 @@ public function testOfficialHolidays(): void } $this->assertDefinedHolidays( - $holidays, - self::REGION, - $this->year, + $holidays, + self::REGION, + $this->year, Holiday::TYPE_OFFICIAL ); }