feat(rtt) : add SolidarityDayResolver (Pentecost Monday via computus)
This commit is contained in:
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Service\Rtt;
|
||||||
|
|
||||||
|
use DateTimeImmutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Résout le jour de solidarité (Lundi de Pentecôte) d'une année.
|
||||||
|
*
|
||||||
|
* Pur et déterministe : Pâques via l'algorithme de Meeus/Jones/Butcher (calendrier
|
||||||
|
* grégorien), sans dépendance à l'extension calendar ni au réseau. Lundi de Pentecôte
|
||||||
|
* = dimanche de Pâques + 50 jours.
|
||||||
|
*/
|
||||||
|
final class SolidarityDayResolver
|
||||||
|
{
|
||||||
|
public function pentecostMonday(int $year): DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->easterSunday($year)->modify('+50 days');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function easterSunday(int $year): DateTimeImmutable
|
||||||
|
{
|
||||||
|
$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 DateTimeImmutable(sprintf('%04d-%02d-%02d', $year, $month, $day));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Service\Rtt;
|
||||||
|
|
||||||
|
use App\Service\Rtt\SolidarityDayResolver;
|
||||||
|
use PHPUnit\Framework\Attributes\DataProvider;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class SolidarityDayResolverTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Lundi de Pentecôte = dimanche de Pâques + 50 jours.
|
||||||
|
* 2024 : Pâques 31/03 → 20/05 ; 2025 : Pâques 20/04 → 09/06 ; 2026 : Pâques 05/04 → 25/05.
|
||||||
|
*/
|
||||||
|
#[DataProvider('pentecostCases')]
|
||||||
|
public function testPentecostMonday(int $year, string $expected): void
|
||||||
|
{
|
||||||
|
$resolver = new SolidarityDayResolver();
|
||||||
|
|
||||||
|
self::assertSame($expected, $resolver->pentecostMonday($year)->format('Y-m-d'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return iterable<string, array{int, string}>
|
||||||
|
*/
|
||||||
|
public static function pentecostCases(): iterable
|
||||||
|
{
|
||||||
|
yield '2024' => [2024, '2024-05-20'];
|
||||||
|
|
||||||
|
yield '2025' => [2025, '2025-06-09'];
|
||||||
|
|
||||||
|
yield '2026' => [2026, '2026-05-25'];
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user