Skip to content

Commit

Permalink
Merge pull request #224 from spatie/3.x-merge
Browse files Browse the repository at this point in the history
Merge master into 3.x
  • Loading branch information
kylekatarnls committed Nov 5, 2023
2 parents 797824b + b630314 commit 036c228
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php: ['7.4', '8.0', '8.1']
php: ['7.4', '8.0', '8.1', '8.2', '8.3']
setup: ['lowest', 'stable']

name: PHP ${{ matrix.php }} - ${{ matrix.setup || 'stable' }}
Expand Down
79 changes: 68 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ Returns an `OpeningHoursForDay` object for a regular day. A day is lowercase str
$openingHours->forDay('monday');
```

#### `OpeningHours::forDate(DateTime $dateTime): Spatie\OpeningHours\OpeningHoursForDay`
#### `OpeningHours::forDate(DateTimeInterface $dateTime): Spatie\OpeningHours\OpeningHoursForDay`

Returns an `OpeningHoursForDay` object for a specific date. It looks for an exception on that day, and otherwise it returns the opening hours based on the regular schedule.

Expand Down Expand Up @@ -368,15 +368,15 @@ Checks if the business is closed on a day in the regular schedule.
$openingHours->isClosedOn('sunday');
```

#### `OpeningHours::isOpenAt(DateTime $dateTime): bool`
#### `OpeningHours::isOpenAt(DateTimeInterface $dateTime): bool`

Checks if the business is open on a specific day, at a specific time.

```php
$openingHours->isOpenAt(new DateTime('2016-26-09 20:00'));
```

#### `OpeningHours::isClosedAt(DateTime $dateTime): bool`
#### `OpeningHours::isClosedAt(DateTimeInterface $dateTime): bool`

Checks if the business is closed on a specific day, at a specific time.

Expand All @@ -400,33 +400,90 @@ Checks if the business is closed right now.
$openingHours->isClosed();
```

#### `OpeningHours::nextOpen(DateTimeInterface $dateTime) : DateTime`
#### `OpeningHours::nextOpen`

Returns next open DateTime from the given DateTime
```php
OpeningHours::nextOpen(
?DateTimeInterface $dateTime = null,
?DateTimeInterface $searchUntil = null,
?DateTimeInterface $cap = null,
) : DateTimeInterface`
```

Returns next open `DateTime` from the given `DateTime` (`$dateTime` or from now if this parameter is null or omitted).

If a `DateTimeImmutable` object is passed, a `DateTimeImmutable` object is returned.

Set `$searchUntil` to a date to throw an exception if no open time can be found before this moment.

Set `$cap` to a date so if no open time can be found before this moment, `$cap` is returned.

```php
$openingHours->nextOpen(new DateTime('2016-12-24 11:00:00'));
```
`

#### `OpeningHours::nextClose`

```php
OpeningHours::nextClose(
?DateTimeInterface $dateTime = null,
?DateTimeInterface $searchUntil = null,
?DateTimeInterface $cap = null,
) : DateTimeInterface`
```

Returns next close `DateTime` from the given `DateTime` (`$dateTime` or from now if this parameter is null or omitted).

If a `DateTimeImmutable` object is passed, a `DateTimeImmutable` object is returned.

#### `OpeningHours::nextClose(DateTimeInterface $dateTime) : DateTime`
Set `$searchUntil` to a date to throw an exception if no closed time can be found before this moment.

Returns next close DateTime from the given DateTime
Set `$cap` to a date so if no closed time can be found before this moment, `$cap` is returned.

```php
$openingHours->nextClose(new DateTime('2016-12-24 11:00:00'));
```

#### `OpeningHours::previousOpen(DateTimeInterface $dateTime) : DateTime`
#### `OpeningHours::previousOpen`

Returns previous open DateTime from the given DateTime
```php
OpeningHours::previousOpen(
?DateTimeInterface $dateTime = null,
?DateTimeInterface $searchUntil = null,
?DateTimeInterface $cap = null,
) : DateTimeInterface`
```

Returns previous open `DateTime` from the given `DateTime` (`$dateTime` or from now if this parameter is null or omitted).

If a `DateTimeImmutable` object is passed, a `DateTimeImmutable` object is returned.

Set `$searchUntil` to a date to throw an exception if no open time can be found after this moment.

Set `$cap` to a date so if no open time can be found after this moment, `$cap` is returned.

```php
$openingHours->previousOpen(new DateTime('2016-12-24 11:00:00'));
```

#### `OpeningHours::previousClose(DateTimeInterface $dateTime) : DateTime`
#### `OpeningHours::previousClose`

```php
OpeningHours::previousClose(
?DateTimeInterface $dateTime = null,
?DateTimeInterface $searchUntil = null,
?DateTimeInterface $cap = null,
) : DateTimeInterface`
```

Returns previous close `DateTime` from the given `DateTime` (`$dateTime` or from now if this parameter is null or omitted).

If a `DateTimeImmutable` object is passed, a `DateTimeImmutable` object is returned.

Set `$searchUntil` to a date to throw an exception if no closed time can be found after this moment.

Returns previous close DateTime from the given DateTime
Set `$cap` to a date so if no closed time can be found after this moment, `$cap` is returned.

```php
$openingHours->nextClose(new DateTime('2016-12-24 11:00:00'));
Expand Down
4 changes: 2 additions & 2 deletions src/DateTimeRange.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ protected function __construct(DateTimeInterface $date, Time $start, Time $end,
$start > $date->format(self::TIME_FORMAT)
? ' - 1 day'
: ''
));
));
$endDate = $this->copyAndModify($date, $end.(
$end < $date->format(self::TIME_FORMAT)
? ' + 1 day'
: ''
));
));
parent::__construct(
Time::fromString($start, $start->getData(), $startDate),
Time::fromString($end, $start->getData(), $endDate),
Expand Down
13 changes: 13 additions & 0 deletions src/Exceptions/SearchLimitReached.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Spatie\OpeningHours\Exceptions;

use DateTimeInterface;

class SearchLimitReached extends Exception
{
public static function forDate(DateTimeInterface $dateTime): self
{
return new self('Search reached the limit: '.$dateTime->format('Y-m-d H:i:s.u e'));
}
}
5 changes: 3 additions & 2 deletions src/Helpers/DiffTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ private function diffInSeconds(string $stateCheckMethod, string $nextDateMethod,

while ($date < $endDate) {
if ($this->$stateCheckMethod($date)) {
$date = $this->$skipDateMethod($date);
$date = $this->$skipDateMethod($date, null, $endDate);

continue;
}

$nextDate = min($endDate, $this->$nextDateMethod($date));
$nextDate = min($endDate, $this->$nextDateMethod($date, null, $endDate));
$time += floatval($nextDate->format('U.u')) - floatval($date->format('U.u'));
$date = $nextDate;
}
Expand Down
68 changes: 58 additions & 10 deletions src/OpeningHours.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Spatie\OpeningHours\Exceptions\InvalidDayName;
use Spatie\OpeningHours\Exceptions\InvalidTimezone;
use Spatie\OpeningHours\Exceptions\MaximumLimitExceeded;
use Spatie\OpeningHours\Exceptions\SearchLimitReached;
use Spatie\OpeningHours\Helpers\Arr;
use Spatie\OpeningHours\Helpers\DataTrait;
use Spatie\OpeningHours\Helpers\DateTimeCopier;
Expand All @@ -24,7 +25,7 @@ class OpeningHours

use DataTrait, DateTimeCopier, DiffTrait;

/** @var \Spatie\OpeningHours\Day[] */
/** @var \Spatie\OpeningHours\OpeningHoursForDay[] */
protected array $openingHours = [];

/** @var \Spatie\OpeningHours\OpeningHoursForDay[] */
Expand Down Expand Up @@ -190,7 +191,7 @@ public function setDateTimeClass(?string $dateTimeClass = null): self
*
* Replace the whole metadata handled by OpeningHours.
*
* @param $data
* @param $data
* @return $this
*/
public function setData($data): self
Expand Down Expand Up @@ -476,8 +477,11 @@ public function currentOpenRangeEnd(DateTimeInterface $dateTime): ?DateTimeInter
);
}

public function nextOpen(?DateTimeInterface $dateTime = null): DateTimeInterface
{
public function nextOpen(
?DateTimeInterface $dateTime = null,
?DateTimeInterface $searchUntil = null,
?DateTimeInterface $cap = null
): DateTimeInterface {
$outputTimezone = $this->getOutputTimezone($dateTime);
$dateTime = $this->applyTimezone($dateTime ?? new $this->dateTimeClass());
$dateTime = $this->copyDateTime($dateTime);
Expand All @@ -501,6 +505,14 @@ public function nextOpen(?DateTimeInterface $dateTime = null): DateTimeInterface
return $this->getDateWithTimezone($dateTime, $outputTimezone);
}

if ($cap && $dateTime > $cap) {
return $cap;
}

if ($searchUntil && $dateTime > $searchUntil) {
throw SearchLimitReached::forDate($searchUntil);
}

$openingHoursForDay = $this->forDate($dateTime);

$nextOpen = $openingHoursForDay->nextOpen(PreciseTime::fromDateTime($dateTime));
Expand All @@ -523,21 +535,27 @@ public function nextOpen(?DateTimeInterface $dateTime = null): DateTimeInterface
);
}

public function nextClose(?DateTimeInterface $dateTime = null): DateTimeInterface
{
public function nextClose(
?DateTimeInterface $dateTime = null,
?DateTimeInterface $searchUntil = null,
?DateTimeInterface $cap = null
): DateTimeInterface {
$outputTimezone = $this->getOutputTimezone($dateTime);
$dateTime = $this->applyTimezone($dateTime ?? new $this->dateTimeClass());
$dateTime = $this->copyDateTime($dateTime);
$nextClose = null;

if ($this->overflow) {
$dateTimeMinus1Day = $this->yesterday($dateTime);
$openingHoursForDayBefore = $this->forDate($dateTimeMinus1Day);

if ($openingHoursForDayBefore->isOpenAtNight(PreciseTime::fromDateTime($dateTimeMinus1Day))) {
$nextClose = $openingHoursForDayBefore->nextClose(PreciseTime::fromDateTime($dateTime));
}
}

$openingHoursForDay = $this->forDate($dateTime);

if (! $nextClose) {
$nextClose = $openingHoursForDay->nextClose(PreciseTime::fromDateTime($dateTime));

Expand All @@ -564,6 +582,14 @@ public function nextClose(?DateTimeInterface $dateTime = null): DateTimeInterfac
return $this->getDateWithTimezone($dateTime, $outputTimezone);
}

if ($cap && $dateTime > $cap) {
return $cap;
}

if ($searchUntil && $dateTime > $searchUntil) {
throw SearchLimitReached::forDate($searchUntil);
}

$openingHoursForDay = $this->forDate($dateTime);

$nextClose = $openingHoursForDay->nextClose(PreciseTime::fromDateTime($dateTime));
Expand All @@ -577,8 +603,11 @@ public function nextClose(?DateTimeInterface $dateTime = null): DateTimeInterfac
);
}

public function previousOpen(DateTimeInterface $dateTime): DateTimeInterface
{
public function previousOpen(
DateTimeInterface $dateTime,
DateTimeInterface $searchUntil = null,
DateTimeInterface $cap = null
): DateTimeInterface {
$outputTimezone = $this->getOutputTimezone($dateTime);
$dateTime = $this->copyDateTime($this->applyTimezone($dateTime));
$openingHoursForDay = $this->forDate($dateTime);
Expand All @@ -602,6 +631,14 @@ public function previousOpen(DateTimeInterface $dateTime): DateTimeInterface
return $this->getDateWithTimezone($midnight, $outputTimezone);
}

if ($cap && $dateTime < $cap) {
return $cap;
}

if ($searchUntil && $dateTime < $searchUntil) {
throw SearchLimitReached::forDate($searchUntil);
}

$previousOpen = $openingHoursForDay->previousOpen(PreciseTime::fromDateTime($dateTime));
}

Expand All @@ -613,8 +650,11 @@ public function previousOpen(DateTimeInterface $dateTime): DateTimeInterface
);
}

public function previousClose(DateTimeInterface $dateTime): DateTimeInterface
{
public function previousClose(
DateTimeInterface $dateTime,
DateTimeInterface $searchUntil = null,
DateTimeInterface $cap = null
): DateTimeInterface {
$outputTimezone = $this->getOutputTimezone($dateTime);
$dateTime = $this->copyDateTime($this->applyTimezone($dateTime));
$previousClose = null;
Expand Down Expand Up @@ -649,6 +689,14 @@ public function previousClose(DateTimeInterface $dateTime): DateTimeInterface
return $this->getDateWithTimezone($midnight, $outputTimezone);
}

if ($cap && $dateTime < $cap) {
return $cap;
}

if ($searchUntil && $dateTime < $searchUntil) {
throw SearchLimitReached::forDate($searchUntil);
}

$previousClose = $openingHoursForDay->previousClose(PreciseTime::fromDateTime($dateTime));
}

Expand Down
14 changes: 9 additions & 5 deletions src/Time.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,15 @@ public function toDateTime(DateTimeInterface $date = null): DateTimeInterface
public function format(string $format = self::TIME_FORMAT, $timezone = null): string
{
$date = $this->date ?: ($timezone
? new DateTime('1970-01-01 00:00:00', $timezone instanceof DateTimeZone
? new DateTimeImmutable('1970-01-01 00:00:00', $timezone instanceof DateTimeZone
? $timezone
: new DateTimeZone($timezone)
)
: null
);

if ($this->hours === 24 && $this->minutes === 0 && substr($format, 0, 3) === self::TIME_FORMAT) {
return '24:00'.(strlen($format) > 3
? ($date ?? new DateTimeImmutable('1970-01-01 00:00:00'))->format(substr($format, 3))
: ''
);
return '24:00'.$this->formatSecond($format, $date);
}

return $this->toDateTime($date)->format($format);
Expand All @@ -116,4 +113,11 @@ public function __toString(): string
{
return $this->format();
}

private function formatSecond(string $format, ?DateTimeImmutable $date = null): string
{
return strlen($format) > 3
? ($date ?? new DateTimeImmutable('1970-01-01 00:00:00'))->format(substr($format, 3))
: '';
}
}
Loading

0 comments on commit 036c228

Please sign in to comment.