diff --git a/src/OpeningHours.php b/src/OpeningHours.php index 221f491..065f3c5 100644 --- a/src/OpeningHours.php +++ b/src/OpeningHours.php @@ -817,6 +817,10 @@ protected function readDatesRange(string $key): iterable $dashChunks = explode('-', $key); $chunksCount = count($dashChunks); + if ($chunksCount === 2) { + return $this->daysBetween(trim($dashChunks[0]), trim($dashChunks[1])); + } + if ($chunksCount >= 4) { $middle = ceil($chunksCount / 2); @@ -829,12 +833,40 @@ protected function readDatesRange(string $key): iterable return [$key]; } - protected function daysBetween(string $start, string $end): DatePeriod + /** @return Generator */ + protected function daysBetween(string $start, string $end): Generator { + $count = count(explode('-', $start)); + + if ($count === 2) { + // Use an arbitrary leap year + $start = "2024-$start"; + $end = "2024-$end"; + } + $startDate = new DateTimeImmutable($start); $endDate = $startDate->modify($end)->modify('+12 hours'); - return new DatePeriod($startDate, new DateInterval('P1D'), $endDate); + if ($endDate < $startDate) { + echo "TOO CLOSE\n"; + var_dump($startDate, $endDate); + exit; + } + + if ($endDate > $startDate->modify('+30 days')) { + echo "TOO FAR\n"; + var_dump($startDate, $endDate); + exit; + } + + $format = ([ + 2 => 'm-d', + 3 => 'Y-m-d', + ])[$count] ?? 'l'; + + foreach (new DatePeriod($startDate, new DateInterval('P1D'), $endDate) as $date) { + yield $date->format($format); + } } protected function setOpeningHoursFromStrings(string $day, array $openingHours): void diff --git a/tests/OpeningHoursTest.php b/tests/OpeningHoursTest.php index 001e970..bc9affb 100644 --- a/tests/OpeningHoursTest.php +++ b/tests/OpeningHoursTest.php @@ -6,6 +6,7 @@ use DateTimeImmutable; use DateTimeZone; use PHPUnit\Framework\TestCase; +use Spatie\OpeningHours\Exceptions\InvalidDateRange; use Spatie\OpeningHours\Exceptions\MaximumLimitExceeded; use Spatie\OpeningHours\Exceptions\SearchLimitReached; use Spatie\OpeningHours\OpeningHours; @@ -1583,4 +1584,45 @@ public function testSearchWithEmptyHours() $this->assertSame(0.0, $minutes); } + + public function testRanges() + { + $openingHours = OpeningHours::create([ + 'monday - wednesday' => ['08:30-12:00', '14:30-16:00'], + 'thursday to friday' => ['14:30-18:00'], + 'saturday-sunday' => [], + 'exceptions' => [ + '2016-11-11-2016-11-14' => ['09:00-12:00'], + '11-30-12-01' => ['09:00-14:00'], + '12-24 to 12-26' => [], + ], + ]); + + $this->assertSame([ + 'monday' => '08:30-12:00,14:30-16:00', + 'tuesday' => '08:30-12:00,14:30-16:00', + 'wednesday' => '08:30-12:00,14:30-16:00', + 'thursday' => '14:30-18:00', + 'friday' => '14:30-18:00', + 'saturday' => '', + 'sunday' => '', + ], array_map( + static fn (OpeningHoursForDay $day) => (string) $day, + $openingHours->forWeek(), + )); + $this->assertSame('09:00-12:00', (string) $openingHours->forDate(new DateTimeImmutable('2016-11-12 11:00'))); + $this->assertSame('09:00-14:00', (string) $openingHours->forDate(new DateTimeImmutable('2023-12-01 11:00'))); + $this->assertSame('', (string) $openingHours->forDate(new DateTimeImmutable('2024-12-25 11:00'))); + } + + public function testRangesOverlap() + { + $this->expectException(InvalidDateRange::class); + $this->expectExceptionMessage('Unable to record `tuesday to friday` as it would override `tuesday`.'); + + OpeningHours::create([ + 'monday - wednesday' => ['08:30-12:00', '14:30-16:00'], + 'tuesday to friday' => ['14:30-18:00'], + ]); + } }