Skip to content

Commit

Permalink
Fix #73 and support immutable dates
Browse files Browse the repository at this point in the history
  • Loading branch information
kylekatarnls committed Oct 30, 2018
1 parent 5f72cb5 commit 262ff9a
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ build
composer.lock
docs
vendor
.idea
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@
},
"config": {
"sort-packages": true
}
}
}
25 changes: 17 additions & 8 deletions src/OpeningHours.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use DateTime;
use DateTimeZone;
use DateTimeImmutable;
use DateTimeInterface;
use Spatie\OpeningHours\Helpers\Arr;
use Spatie\OpeningHours\Exceptions\Exception;
Expand Down Expand Up @@ -150,13 +151,17 @@ public function isClosed(): bool
return $this->isClosedAt(new DateTime());
}

public function nextOpen(DateTimeInterface $dateTime): DateTime
public function nextOpen(DateTimeInterface $dateTime): DateTimeInterface
{
if (! ($dateTime instanceof DateTimeImmutable)) {
$dateTime = clone $dateTime;
}

$openingHoursForDay = $this->forDate($dateTime);
$nextOpen = $openingHoursForDay->nextOpen(Time::fromDateTime($dateTime));

while ($nextOpen == false) {
$dateTime
while ($nextOpen === false) {
$dateTime = $dateTime
->modify('+1 day')
->setTime(0, 0, 0);

Expand All @@ -166,18 +171,22 @@ public function nextOpen(DateTimeInterface $dateTime): DateTime
}

$nextDateTime = $nextOpen->toDateTime();
$dateTime->setTime($nextDateTime->format('G'), $nextDateTime->format('i'), 0);
$dateTime = $dateTime->setTime($nextDateTime->format('G'), $nextDateTime->format('i'), 0);

return $dateTime;
}

public function nextClose(DateTimeInterface $dateTime): DateTime
public function nextClose(DateTimeInterface $dateTime): DateTimeInterface
{
if (! ($dateTime instanceof DateTimeImmutable)) {
$dateTime = clone $dateTime;
}

$openingHoursForDay = $this->forDate($dateTime);
$nextClose = $openingHoursForDay->nextClose(Time::fromDateTime($dateTime));

while ($nextClose == false) {
$dateTime
while ($nextClose === false) {
$dateTime = $dateTime
->modify('+1 day')
->setTime(0, 0, 0);

Expand All @@ -187,7 +196,7 @@ public function nextClose(DateTimeInterface $dateTime): DateTime
}

$nextDateTime = $nextClose->toDateTime();
$dateTime->setTime($nextDateTime->format('G'), $nextDateTime->format('i'), 0);
$dateTime = $dateTime->setTime($nextDateTime->format('G'), $nextDateTime->format('i'), 0);

return $dateTime;
}
Expand Down
8 changes: 8 additions & 0 deletions src/OpeningHoursForDay.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ public function nextOpen(Time $time)
{
foreach ($this->openingHours as $timeRange) {
if ($nextOpen = $this->findNextOpenInWorkingHours($time, $timeRange)) {
reset($timeRange);

return $nextOpen;
}

if ($nextOpen = $this->findNextOpenInFreeTime($time, $timeRange)) {
reset($timeRange);

return $nextOpen;
}
}
Expand All @@ -59,10 +63,14 @@ public function nextClose(Time $time)
{
foreach ($this->openingHours as $timeRange) {
if ($nextClose = $this->findNextCloseInWorkingHours($time, $timeRange)) {
reset($timeRange);

return $nextClose;
}

if ($nextClose = $this->findNextCloseInFreeTime($time, $timeRange)) {
reset($timeRange);

return $nextClose;
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/Time.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Spatie\OpeningHours;

use DateTime;
use DateTimeImmutable;
use DateTimeInterface;
use Spatie\OpeningHours\Exceptions\InvalidTimeString;

Expand Down Expand Up @@ -83,9 +84,13 @@ public function diff(self $time): \DateInterval
return $this->toDateTime()->diff($time->toDateTime());
}

public function toDateTime(DateTime $date = null): DateTime
public function toDateTime(DateTimeInterface $date = null): DateTimeInterface
{
$date = $date ? (clone $date) : new DateTime('1970-01-01 00:00:00');
if (! $date) {
$date = new DateTime('1970-01-01 00:00:00');
} elseif (! ($date instanceof DateTimeImmutable)) {
$date = clone $date;
}

return $date->setTime($this->hours, $this->minutes);
}
Expand Down
2 changes: 2 additions & 0 deletions tests/OpeningHoursFillTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Spatie\OpeningHours\Test;

use DateTime;
use DateTimeImmutable;
use Spatie\OpeningHours\Day;
use PHPUnit\Framework\TestCase;
use Spatie\OpeningHours\TimeRange;
Expand Down Expand Up @@ -44,6 +45,7 @@ public function it_fills_opening_hours()
$this->assertEquals((string) $openingHours->forDay('friday')[0], '09:00-20:00');

$this->assertCount(0, $openingHours->forDate(new DateTime('2016-09-26 11:00:00')));
$this->assertCount(0, $openingHours->forDate(new DateTimeImmutable('2016-09-26 11:00:00')));
}

/** @test */
Expand Down
106 changes: 102 additions & 4 deletions tests/OpeningHoursTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use DateTime;
use DateTimeZone;
use DateTimeImmutable;
use PHPUnit\Framework\TestCase;
use Spatie\OpeningHours\OpeningHours;

Expand Down Expand Up @@ -131,6 +132,14 @@ public function it_can_return_the_opening_hours_for_a_specific_date()
$this->assertEquals('09:00-18:00', $openingHoursForMonday1909[0]);

$this->assertCount(0, $openingHoursForMonday2609);

$openingHoursForMonday1909 = $openingHours->forDate(new DateTimeImmutable('2016-09-19 00:00:00'));
$openingHoursForMonday2609 = $openingHours->forDate(new DateTimeImmutable('2016-09-26 00:00:00'));

$this->assertCount(1, $openingHoursForMonday1909);
$this->assertEquals('09:00-18:00', $openingHoursForMonday1909[0]);

$this->assertCount(0, $openingHoursForMonday2609);
}

/** @test */
Expand All @@ -144,6 +153,10 @@ public function it_can_determine_that_its_open_at_a_certain_date_and_time()
$this->assertTrue($openingHours->isOpenAt($shouldBeOpen));
$this->assertFalse($openingHours->isClosedAt($shouldBeOpen));

$shouldBeOpen = new DateTimeImmutable('2016-09-26 11:00:00');
$this->assertTrue($openingHours->isOpenAt($shouldBeOpen));
$this->assertFalse($openingHours->isClosedAt($shouldBeOpen));

$shouldBeOpenAlternativeDate = date_create_immutable('2016-09-26 11:12:13.123456');
$this->assertTrue($openingHours->isOpenAt($shouldBeOpenAlternativeDate));
$this->assertFalse($openingHours->isClosedAt($shouldBeOpenAlternativeDate));
Expand All @@ -152,9 +165,17 @@ public function it_can_determine_that_its_open_at_a_certain_date_and_time()
$this->assertFalse($openingHours->isOpenAt($shouldBeClosedBecauseOfTime));
$this->assertTrue($openingHours->isClosedAt($shouldBeClosedBecauseOfTime));

$shouldBeClosedBecauseOfTime = new DateTimeImmutable('2016-09-26 20:00:00');
$this->assertFalse($openingHours->isOpenAt($shouldBeClosedBecauseOfTime));
$this->assertTrue($openingHours->isClosedAt($shouldBeClosedBecauseOfTime));

$shouldBeClosedBecauseOfDay = new DateTime('2016-09-27 11:00:00');
$this->assertFalse($openingHours->isOpenAt($shouldBeClosedBecauseOfDay));
$this->assertTrue($openingHours->isClosedAt($shouldBeClosedBecauseOfDay));

$shouldBeClosedBecauseOfDay = new DateTimeImmutable('2016-09-27 11:00:00');
$this->assertFalse($openingHours->isOpenAt($shouldBeClosedBecauseOfDay));
$this->assertTrue($openingHours->isClosedAt($shouldBeClosedBecauseOfDay));
}

/** @test */
Expand All @@ -170,6 +191,10 @@ public function it_can_determine_that_its_open_at_a_certain_date_and_time_on_an_
$shouldBeClosed = new DateTime('2016-09-26 11:00:00');
$this->assertFalse($openingHours->isOpenAt($shouldBeClosed));
$this->assertTrue($openingHours->isClosedAt($shouldBeClosed));

$shouldBeClosed = new DateTimeImmutable('2016-09-26 11:00:00');
$this->assertFalse($openingHours->isOpenAt($shouldBeClosed));
$this->assertTrue($openingHours->isClosedAt($shouldBeClosed));
}

/** @test */
Expand All @@ -188,13 +213,25 @@ public function it_can_determine_that_its_open_at_a_certain_date_and_time_on_an_
$this->assertFalse($openingHours->isOpenAt($closedOnNewYearDay));
$this->assertTrue($openingHours->isClosedAt($closedOnNewYearDay));

$closedOnNewYearDay = new DateTimeImmutable('2017-01-01 11:00:00');
$this->assertFalse($openingHours->isOpenAt($closedOnNewYearDay));
$this->assertTrue($openingHours->isClosedAt($closedOnNewYearDay));

$closedOnSecondChristmasDay = new DateTime('2025-12-16 12:00:00');
$this->assertFalse($openingHours->isOpenAt($closedOnSecondChristmasDay));
$this->assertTrue($openingHours->isClosedAt($closedOnSecondChristmasDay));

$closedOnSecondChristmasDay = new DateTimeImmutable('2025-12-16 12:00:00');
$this->assertFalse($openingHours->isOpenAt($closedOnSecondChristmasDay));
$this->assertTrue($openingHours->isClosedAt($closedOnSecondChristmasDay));

$openOnChristmasMorning = new DateTime('2025-12-25 10:00:00');
$this->assertTrue($openingHours->isOpenAt($openOnChristmasMorning));
$this->assertFalse($openingHours->isClosedAt($openOnChristmasMorning));

$openOnChristmasMorning = new DateTimeImmutable('2025-12-25 10:00:00');
$this->assertTrue($openingHours->isOpenAt($openOnChristmasMorning));
$this->assertFalse($openingHours->isClosedAt($openOnChristmasMorning));
}

/** @test */
Expand All @@ -213,9 +250,17 @@ public function it_can_prioritize_exceptions_by_giving_full_dates_priority()
$this->assertTrue($openingHours->isOpenAt($openOnNewYearDay2018));
$this->assertFalse($openingHours->isClosedAt($openOnNewYearDay2018));

$openOnNewYearDay2018 = new DateTimeImmutable('2018-01-01 11:00:00');
$this->assertTrue($openingHours->isOpenAt($openOnNewYearDay2018));
$this->assertFalse($openingHours->isClosedAt($openOnNewYearDay2018));

$closedOnNewYearDay2019 = new DateTime('2019-01-01 11:00:00');
$this->assertFalse($openingHours->isOpenAt($closedOnNewYearDay2019));
$this->assertTrue($openingHours->isClosedAt($closedOnNewYearDay2019));

$closedOnNewYearDay2019 = new DateTimeImmutable('2019-01-01 11:00:00');
$this->assertFalse($openingHours->isOpenAt($closedOnNewYearDay2019));
$this->assertTrue($openingHours->isClosedAt($closedOnNewYearDay2019));
}

/** @test */
Expand All @@ -229,6 +274,11 @@ public function it_can_determine_next_open_hours_from_non_working_date_time()

$this->assertInstanceOf(DateTime::class, $nextTimeOpen);
$this->assertEquals('2016-09-26 13:00:00', $nextTimeOpen->format('Y-m-d H:i:s'));

$nextTimeOpen = $openingHours->nextOpen(new DateTimeImmutable('2016-09-26 12:00:00'));

$this->assertInstanceOf(DateTimeImmutable::class, $nextTimeOpen);
$this->assertEquals('2016-09-26 13:00:00', $nextTimeOpen->format('Y-m-d H:i:s'));
}

/** @test */
Expand All @@ -242,6 +292,11 @@ public function it_can_determine_next_close_hours_from_non_working_date_time()

$this->assertInstanceOf(DateTime::class, $nextTimeOpen);
$this->assertEquals('2016-09-26 19:00:00', $nextTimeOpen->format('Y-m-d H:i:s'));

$nextTimeOpen = $openingHours->nextClose(new DateTimeImmutable('2016-09-26 12:00:00'));

$this->assertInstanceOf(DateTimeImmutable::class, $nextTimeOpen);
$this->assertEquals('2016-09-26 19:00:00', $nextTimeOpen->format('Y-m-d H:i:s'));
}

/** @test */
Expand All @@ -256,20 +311,32 @@ public function it_can_determine_next_open_hours_from_working_date_time()

$this->assertInstanceOf(DateTime::class, $nextTimeOpen);
$this->assertEquals('2016-09-27 10:00:00', $nextTimeOpen->format('Y-m-d H:i:s'));

$nextTimeOpen = $openingHours->nextOpen(new DateTimeImmutable('2016-09-26 16:00:00'));

$this->assertInstanceOf(DateTimeImmutable::class, $nextTimeOpen);
$this->assertEquals('2016-09-27 10:00:00', $nextTimeOpen->format('Y-m-d H:i:s'));
}

/** @test */
/** @test
* @group i
*/
public function it_can_determine_next_close_hours_from_working_date_time()
{
$openingHours = OpeningHours::create([
'monday' => ['09:00-11:00', '13:00-19:00'],
'tuesday' => ['10:00-11:00', '14:00-19:00'],
]);

$nextTimeOpen = $openingHours->nextClose(new DateTime('2016-09-26 16:00:00'));
$nextTimeClose = $openingHours->nextClose(new DateTime('2016-09-26 16:00:00'));

$this->assertInstanceOf(DateTime::class, $nextTimeOpen);
$this->assertEquals('2016-09-26 19:00:00', $nextTimeOpen->format('Y-m-d H:i:s'));
$this->assertInstanceOf(DateTime::class, $nextTimeClose);
$this->assertEquals('2016-09-26 19:00:00', $nextTimeClose->format('Y-m-d H:i:s'));

$nextTimeClose = $openingHours->nextClose(new DateTimeImmutable('2016-09-26 16:00:00'));

$this->assertInstanceOf(DateTimeImmutable::class, $nextTimeClose);
$this->assertEquals('2016-09-26 19:00:00', $nextTimeClose->format('Y-m-d H:i:s'));
}

/** @test */
Expand All @@ -287,6 +354,11 @@ public function it_can_determine_next_open_hours_from_early_morning()

$this->assertInstanceOf(DateTime::class, $nextTimeOpen);
$this->assertEquals('2016-09-27 10:00:00', $nextTimeOpen->format('Y-m-d H:i:s'));

$nextTimeOpen = $openingHours->nextOpen(new DateTimeImmutable('2016-09-26 04:00:00'));

$this->assertInstanceOf(DateTimeImmutable::class, $nextTimeOpen);
$this->assertEquals('2016-09-27 10:00:00', $nextTimeOpen->format('Y-m-d H:i:s'));
}

/** @test */
Expand All @@ -304,6 +376,11 @@ public function it_can_determine_next_close_hours_from_early_morning()

$this->assertInstanceOf(DateTime::class, $nextTimeOpen);
$this->assertEquals('2016-09-27 11:00:00', $nextTimeOpen->format('Y-m-d H:i:s'));

$nextTimeOpen = $openingHours->nextClose(new DateTimeImmutable('2016-09-26 04:00:00'));

$this->assertInstanceOf(DateTimeImmutable::class, $nextTimeOpen);
$this->assertEquals('2016-09-27 11:00:00', $nextTimeOpen->format('Y-m-d H:i:s'));
}

/** @test */
Expand Down Expand Up @@ -332,9 +409,27 @@ public function it_can_set_the_timezone_on_the_openings_hours_object()
$this->assertFalse($openingHours->isOpenAt(new DateTime('2016-11-14 15:59', new DateTimeZone('America/Denver'))));
$this->assertTrue($openingHours->isOpenAt(new DateTime('2016-10-10 09:59', new DateTimeZone('America/Denver'))));

$this->assertTrue($openingHours->isOpenAt(new DateTimeImmutable('2016-10-10 10:00')));
$this->assertTrue($openingHours->isOpenAt(new DateTimeImmutable('2016-10-10 15:59')));
$this->assertTrue($openingHours->isOpenAt(new DateTimeImmutable('2016-10-10 08:00')));
$this->assertFalse($openingHours->isOpenAt(new DateTimeImmutable('2016-10-10 06:00')));

$this->assertFalse($openingHours->isOpenAt(new DateTimeImmutable('2016-10-10 06:00', new DateTimeZone('Europe/Amsterdam'))));
$this->assertTrue($openingHours->isOpenAt(new DateTimeImmutable('2016-10-10 09:00', new DateTimeZone('Europe/Amsterdam'))));
$this->assertTrue($openingHours->isOpenAt(new DateTimeImmutable('2016-10-10 17:59', new DateTimeZone('Europe/Amsterdam'))));

$this->assertFalse($openingHours->isOpenAt(new DateTime('2016-11-14 17:59', new DateTimeZone('Europe/Amsterdam'))));
$this->assertTrue($openingHours->isOpenAt(new DateTime('2016-11-14 12:59', new DateTimeZone('Europe/Amsterdam'))));

$this->assertFalse($openingHours->isOpenAt(new DateTime('2016-11-14 15:59', new DateTimeZone('America/Denver'))));
$this->assertTrue($openingHours->isOpenAt(new DateTime('2016-10-10 09:59', new DateTimeZone('America/Denver'))));

date_default_timezone_set('America/Denver');
$this->assertTrue($openingHours->isOpenAt(new DateTime('2016-10-10 09:59')));
$this->assertFalse($openingHours->isOpenAt(new DateTime('2016-10-10 10:00')));

$this->assertTrue($openingHours->isOpenAt(new DateTimeImmutable('2016-10-10 09:59')));
$this->assertFalse($openingHours->isOpenAt(new DateTimeImmutable('2016-10-10 10:00')));
}

/** @test */
Expand Down Expand Up @@ -419,6 +514,9 @@ public function it_works_when_starting_at_midnight()

$nextTimeOpen = $openingHours->nextOpen(new DateTime());
$this->assertInstanceOf(DateTime::class, $nextTimeOpen);

$nextTimeOpen = $openingHours->nextOpen(new DateTimeImmutable());
$this->assertInstanceOf(DateTimeImmutable::class, $nextTimeOpen);
}

/** @test */
Expand Down
Loading

0 comments on commit 262ff9a

Please sign in to comment.