Passed
Pull Request — master (#8)
by Kevin
17:44
created

BetweenTimeExtension::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 10
cc 1
nc 1
nop 4
crap 1
1
<?php
2
3
namespace Zenstruck\ScheduleBundle\Schedule\Extension;
4
5
use Zenstruck\ScheduleBundle\Schedule\Exception\SkipTask;
6
7
/**
8
 * @author Kevin Bond <[email protected]>
9
 */
10
final class BetweenTimeExtension
11
{
12
    private $startTime;
13
    private $endTime;
14
    private $within;
15
    private $inclusive;
16
17
    private function __construct(string $startTime, string $endTime, bool $within, bool $inclusive)
18 13
    {
19
        $this->startTime = self::normalizeTime($startTime);
20 13
        $this->endTime = self::normalizeTime($endTime);
21 13
        $this->within = $within;
22 13
        $this->inclusive = $inclusive;
23 13
    }
24 13
25
    public function __toString(): string
26 1
    {
27
        if ($this->within) {
28 1
            return "Only run between {$this->startTime} and {$this->endTime}";
29 1
        }
30
31
        return "Only run if not between {$this->startTime} and {$this->endTime}";
32 1
    }
33
34
    public function filter(?\DateTimeZone $timezone): void
35 12
    {
36
        $isBetween = $this->isBetween($timezone);
37 12
38
        if ($this->within && !$isBetween) {
39 12
            throw new SkipTask("Only runs between {$this->startTime} and {$this->endTime}");
40 3
        }
41
42
        if (!$this->within && $isBetween) {
43 9
            throw new SkipTask("Only runs if not between {$this->startTime} and {$this->endTime}");
44 3
        }
45
    }
46 6
47
    public static function whenWithin(string $startTime, string $endTime, bool $inclusive = true): self
48 7
    {
49
        return new self($startTime, $endTime, true, $inclusive);
50 7
    }
51
52
    public static function unlessWithin(string $startTime, string $endTime, bool $inclusive = true): self
53 7
    {
54
        return new self($startTime, $endTime, false, $inclusive);
55 7
    }
56
57
    private function isBetween(?\DateTimeZone $timezone): bool
58 12
    {
59
        [$now, $startTime, $endTime] = [
60
            new \DateTime(\date('Y-m-d H:i:00'), $timezone),
61 12
            self::parseTime($this->startTime, $timezone),
62 12
            self::parseTime($this->endTime, $timezone),
63 12
        ];
64
65
        if ($endTime < $startTime) {
66 12
            // account for overnight
67
            $endTime = $endTime->add(new \DateInterval('P1D'));
68 4
        }
69
70
        if ($this->inclusive) {
71 12
            return $now >= $startTime && $now <= $endTime;
72 8
        }
73
74
        return $now > $startTime && $now < $endTime;
75 4
    }
76
77
    private static function normalizeTime(string $time): string
78 13
    {
79
        return false === \mb_strpos($time, ':') ? "{$time}:00" : $time;
80 13
    }
81
82
    private static function parseTime(string $time, ?\DateTimeZone $timezone): \DateTime
83 12
    {
84
        [$hour, $minute] = \explode(':', $time, 2);
85 12
86
        return (new \DateTime('today', $timezone))
87 12
            ->add(new \DateInterval("PT{$hour}H{$minute}M"))
88 12
        ;
89
    }
90
}
91