From 12faaaceae25b16c8b40de39ea0d13490cc57581 Mon Sep 17 00:00:00 2001 From: Theron Smith Date: Wed, 17 Jan 2024 13:28:27 -0700 Subject: [PATCH 1/6] Add tests and implementation for calculating Canadian holidays in the Spatie\Holidays package. --- src/Countries/Canada.php | 83 +++++++++++++++++++ .../it_can_calculate_canadian_holidays.snap | 34 ++++++++ tests/Countries/CanadaTest.php | 18 ++++ 3 files changed, 135 insertions(+) create mode 100644 src/Countries/Canada.php create mode 100644 tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap create mode 100644 tests/Countries/CanadaTest.php diff --git a/src/Countries/Canada.php b/src/Countries/Canada.php new file mode 100644 index 00000000..edbf879c --- /dev/null +++ b/src/Countries/Canada.php @@ -0,0 +1,83 @@ + */ + protected function allHolidays(int $year): array + { + $easterSunday = $this->calculateEasterSunday($year); + $goodFriday = $easterSunday->subDays(2); + + return array_merge( + [ + 'New Year\'s Day' => new CarbonImmutable("$year-01-01", 'America/Toronto'), + 'Good Friday' => $goodFriday, + 'Victoria Day' => new CarbonImmutable("last monday of May $year", 'America/Toronto'), + 'Canada Day' => new CarbonImmutable("$year-07-01", 'America/Toronto'), + 'Civic Holiday' => new CarbonImmutable( + "first monday of August $year", 'America/Toronto' + ), + 'Labour Day' => new CarbonImmutable( + "first monday of September $year", 'America/Toronto' + ), + 'National Day for Truth and Reconciliation' => new CarbonImmutable( + "$year-10-30", + 'America/Toronto' + ), + 'Thanksgiving' => new CarbonImmutable( + "second monday of October $year", 'America/Toronto' + ), + 'Remembrance Day' => new CarbonImmutable("$year-11-11", 'America/Toronto'), + 'Christmas Day' => new CarbonImmutable("$year-12-25", 'America/Toronto'), + ], + $this->variableHolidays($year) + ); + } + + /** @return array */ + protected function variableHolidays(int $year): array + { + $victoriaDay = new CarbonImmutable("last monday of May $year", 'America/Toronto'); + if ($victoriaDay->day < 25) { + $victoriaDay = $victoriaDay->addWeek(); + } + + $thanksgiving = new CarbonImmutable("second monday of October $year", 'America/Toronto'); + $boxingDay = new CarbonImmutable($year . '-12-26', 'America/Toronto'); + + return [ + 'Victoria Day' => $victoriaDay, + 'Thanksgiving' => $thanksgiving, + 'Boxing Day' => $boxingDay, + ]; + } + + private function calculateEasterSunday(int $year): CarbonImmutable + { + $a = $year % 19; + $b = intdiv($year, 100); + $c = $year % 100; + $d = intdiv($b, 4); + $e = $b % 4; + $f = intdiv($b + 8, 25); + $g = intdiv($b - $f + 1, 3); + $h = (19 * $a + $b - $d - $g + 15) % 30; + $i = intdiv($c, 4); + $k = $c % 4; + $l = (32 + 2 * $e + 2 * $i - $h - $k) % 7; + $m = intdiv($a + 11 * $h + 22 * $l, 451); + $month = intdiv($h + $l - 7 * $m + 114, 31); + $day = (($h + $l - 7 * $m + 114) % 31) + 1; + + return new CarbonImmutable("$year-$month-$day", 'America/Toronto'); + } +} diff --git a/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap b/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap new file mode 100644 index 00000000..7cecf1cc --- /dev/null +++ b/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap @@ -0,0 +1,34 @@ +[ + { + "name": "New Year's Day", + "date": "2024-01-01" + }, + { + "name": "Good Friday", + "date": "2024-03-29" + }, + { + "name": "Victoria Day", + "date": "2024-05-27" + }, + { + "name": "Canada Day", + "date": "2024-07-01" + }, + { + "name": "Labour Day", + "date": "2024-09-02" + }, + { + "name": "Thanksgiving", + "date": "2024-10-14" + }, + { + "name": "Christmas Day", + "date": "2024-12-25" + }, + { + "name": "Boxing Day", + "date": "2024-12-26" + } +] \ No newline at end of file diff --git a/tests/Countries/CanadaTest.php b/tests/Countries/CanadaTest.php new file mode 100644 index 00000000..0619c4ec --- /dev/null +++ b/tests/Countries/CanadaTest.php @@ -0,0 +1,18 @@ +get(); + + expect($holidays) + ->toBeArray() + ->not()->toBeEmpty(); + + expect(formatDates($holidays))->toMatchSnapshot(); +}); From a11a4db90653d1714a108ece659f56bea152e4db Mon Sep 17 00:00:00 2001 From: Theron Smith Date: Wed, 17 Jan 2024 13:30:43 -0700 Subject: [PATCH 2/6] Add Canadian holidays to the test snapshot for accurate calculations. --- .../it_can_calculate_canadian_holidays.snap | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap b/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap index 7cecf1cc..fbc41a1a 100644 --- a/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap +++ b/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap @@ -15,6 +15,10 @@ "name": "Canada Day", "date": "2024-07-01" }, + { + "name": "Civic Holiday", + "date": "2024-08-05" + }, { "name": "Labour Day", "date": "2024-09-02" @@ -23,6 +27,14 @@ "name": "Thanksgiving", "date": "2024-10-14" }, + { + "name": "National Day for Truth and Reconciliation", + "date": "2024-10-30" + }, + { + "name": "Remembrance Day", + "date": "2024-11-11" + }, { "name": "Christmas Day", "date": "2024-12-25" From 695713f3d6d4f656e5b8795c100988957d7ba881 Mon Sep 17 00:00:00 2001 From: Theron Smith Date: Wed, 17 Jan 2024 15:28:18 -0700 Subject: [PATCH 3/6] Refactor Canada.php to simplify and improve the implementation of holiday dates. --- src/Countries/Canada.php | 52 +++++++++++----------------------------- 1 file changed, 14 insertions(+), 38 deletions(-) diff --git a/src/Countries/Canada.php b/src/Countries/Canada.php index edbf879c..0805f59d 100644 --- a/src/Countries/Canada.php +++ b/src/Countries/Canada.php @@ -14,30 +14,23 @@ public function countryCode(): string /** @return array */ protected function allHolidays(int $year): array { - $easterSunday = $this->calculateEasterSunday($year); - $goodFriday = $easterSunday->subDays(2); - return array_merge( [ - 'New Year\'s Day' => new CarbonImmutable("$year-01-01", 'America/Toronto'), - 'Good Friday' => $goodFriday, - 'Victoria Day' => new CarbonImmutable("last monday of May $year", 'America/Toronto'), - 'Canada Day' => new CarbonImmutable("$year-07-01", 'America/Toronto'), + 'New Year\'s Day' => new CarbonImmutable($year . "-01-01", 'America/Toronto'), + 'Canada Day' => new CarbonImmutable($year . "-07-01", 'America/Toronto'), 'Civic Holiday' => new CarbonImmutable( - "first monday of August $year", 'America/Toronto' + "first monday of August " . $year, 'America/Toronto' ), 'Labour Day' => new CarbonImmutable( - "first monday of September $year", 'America/Toronto' + "first monday of September " . $year, 'America/Toronto' ), 'National Day for Truth and Reconciliation' => new CarbonImmutable( - "$year-10-30", + $year . "-10-30", 'America/Toronto' ), - 'Thanksgiving' => new CarbonImmutable( - "second monday of October $year", 'America/Toronto' - ), - 'Remembrance Day' => new CarbonImmutable("$year-11-11", 'America/Toronto'), - 'Christmas Day' => new CarbonImmutable("$year-12-25", 'America/Toronto'), + 'Remembrance Day' => new CarbonImmutable($year . "-11-11", 'America/Toronto'), + 'Christmas Day' => new CarbonImmutable($year . "-12-25", 'America/Toronto'), + 'Boxing Day' => new CarbonImmutable($year . '-12-26', 'America/Toronto'), ], $this->variableHolidays($year) ); @@ -46,38 +39,21 @@ protected function allHolidays(int $year): array /** @return array */ protected function variableHolidays(int $year): array { + $easterSunday = CarbonImmutable::createFromTimestamp(easter_date($year)) + ->setTimezone('America/Toronto'); + + $goodFriday = $easterSunday->subDays(2); + $victoriaDay = new CarbonImmutable("last monday of May $year", 'America/Toronto'); if ($victoriaDay->day < 25) { $victoriaDay = $victoriaDay->addWeek(); } $thanksgiving = new CarbonImmutable("second monday of October $year", 'America/Toronto'); - $boxingDay = new CarbonImmutable($year . '-12-26', 'America/Toronto'); - return [ 'Victoria Day' => $victoriaDay, + 'Good Friday' => $goodFriday, 'Thanksgiving' => $thanksgiving, - 'Boxing Day' => $boxingDay, ]; } - - private function calculateEasterSunday(int $year): CarbonImmutable - { - $a = $year % 19; - $b = intdiv($year, 100); - $c = $year % 100; - $d = intdiv($b, 4); - $e = $b % 4; - $f = intdiv($b + 8, 25); - $g = intdiv($b - $f + 1, 3); - $h = (19 * $a + $b - $d - $g + 15) % 30; - $i = intdiv($c, 4); - $k = $c % 4; - $l = (32 + 2 * $e + 2 * $i - $h - $k) % 7; - $m = intdiv($a + 11 * $h + 22 * $l, 451); - $month = intdiv($h + $l - 7 * $m + 114, 31); - $day = (($h + $l - 7 * $m + 114) % 31) + 1; - - return new CarbonImmutable("$year-$month-$day", 'America/Toronto'); - } } From 25164ea4753038f222806d0bc52d9ed29fed6c94 Mon Sep 17 00:00:00 2001 From: Theron Smith Date: Wed, 17 Jan 2024 15:34:05 -0700 Subject: [PATCH 4/6] Add Easter Sunday as a Canadian holiday in order to accurately calculate Canadian holidays. --- src/Countries/Canada.php | 1 + .../CanadaTest/it_can_calculate_canadian_holidays.snap | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/Countries/Canada.php b/src/Countries/Canada.php index 0805f59d..04dfba89 100644 --- a/src/Countries/Canada.php +++ b/src/Countries/Canada.php @@ -53,6 +53,7 @@ protected function variableHolidays(int $year): array return [ 'Victoria Day' => $victoriaDay, 'Good Friday' => $goodFriday, + 'Easter Sunday' => $easterSunday, 'Thanksgiving' => $thanksgiving, ]; } diff --git a/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap b/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap index fbc41a1a..f02c28c7 100644 --- a/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap +++ b/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap @@ -7,6 +7,10 @@ "name": "Good Friday", "date": "2024-03-29" }, + { + "name": "Easter Sunday", + "date": "2024-03-31" + }, { "name": "Victoria Day", "date": "2024-05-27" From a464c3ea3fffabce46d7ba461ef9cfe22e37b3d7 Mon Sep 17 00:00:00 2001 From: Theron Smith Date: Wed, 17 Jan 2024 15:36:30 -0700 Subject: [PATCH 5/6] Update National Day for Truth and Reconciliation to September 30th. --- src/Countries/Canada.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Countries/Canada.php b/src/Countries/Canada.php index 04dfba89..034f2eef 100644 --- a/src/Countries/Canada.php +++ b/src/Countries/Canada.php @@ -25,7 +25,7 @@ protected function allHolidays(int $year): array "first monday of September " . $year, 'America/Toronto' ), 'National Day for Truth and Reconciliation' => new CarbonImmutable( - $year . "-10-30", + $year . "-09-30", 'America/Toronto' ), 'Remembrance Day' => new CarbonImmutable($year . "-11-11", 'America/Toronto'), From 4e8fa475801187370134128c7d7ea69ca72498ad Mon Sep 17 00:00:00 2001 From: Theron Smith Date: Wed, 17 Jan 2024 15:55:19 -0700 Subject: [PATCH 6/6] Refactor Easter Sunday to Easter Monday. --- src/Countries/Canada.php | 3 ++- .../it_can_calculate_canadian_holidays.snap | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Countries/Canada.php b/src/Countries/Canada.php index 034f2eef..c7efc9e2 100644 --- a/src/Countries/Canada.php +++ b/src/Countries/Canada.php @@ -43,6 +43,7 @@ protected function variableHolidays(int $year): array ->setTimezone('America/Toronto'); $goodFriday = $easterSunday->subDays(2); + $easterMonday = $easterSunday->addDays(1); $victoriaDay = new CarbonImmutable("last monday of May $year", 'America/Toronto'); if ($victoriaDay->day < 25) { @@ -53,7 +54,7 @@ protected function variableHolidays(int $year): array return [ 'Victoria Day' => $victoriaDay, 'Good Friday' => $goodFriday, - 'Easter Sunday' => $easterSunday, + 'Easter Monday' => $easterMonday, 'Thanksgiving' => $thanksgiving, ]; } diff --git a/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap b/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap index f02c28c7..3168b8ea 100644 --- a/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap +++ b/tests/.pest/snapshots/Countries/CanadaTest/it_can_calculate_canadian_holidays.snap @@ -8,8 +8,8 @@ "date": "2024-03-29" }, { - "name": "Easter Sunday", - "date": "2024-03-31" + "name": "Easter Monday", + "date": "2024-04-01" }, { "name": "Victoria Day", @@ -28,12 +28,12 @@ "date": "2024-09-02" }, { - "name": "Thanksgiving", - "date": "2024-10-14" + "name": "National Day for Truth and Reconciliation", + "date": "2024-09-30" }, { - "name": "National Day for Truth and Reconciliation", - "date": "2024-10-30" + "name": "Thanksgiving", + "date": "2024-10-14" }, { "name": "Remembrance Day",