Lines 92.30% 12 / 13
Methods 83.33% 5 / 6
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 every 100.00% 1 / 1 100.00% 1 / 1 1
 findNextDueAfter 100.00% 6 / 6 100.00% 1 / 1 2
 countMissedBetween 66.66% 2 / 3 0.00% 0 / 1 2.15
 describe 100.00% 1 / 1 100.00% 1 / 1 1
 isRecurring 100.00% 1 / 1 100.00% 1 / 1 1
12final readonly class IntervalSchedule implements ElapsedSchedule
13{
14    private function __construct(public Duration $period) {}
15
16    /** @throws TimeException */
17    public static function every(Duration $period): self
18    {
19        return new self($period->requireAtLeastOneMillisecond('an interval schedule'));
20    }
21
22    public function findNextDueAfter(MonotonicTime $anchor, MonotonicTime $after): MonotonicTime
23    {
24        $first = $anchor->plus($this->period);
25
26        if ($after->isBefore($first)) {
27            return $first;
28        }
29
30        $period = $this->period->toMicroseconds();
31        $elapsed = $after->toMicroseconds() - $first->toMicroseconds();
32
33        return MonotonicTime::fromMicroseconds($first->toMicroseconds() + (intdiv($elapsed, $period) + 1) * $period);
34    }
35
36    public function countMissedBetween(MonotonicTime $due, MonotonicTime $now): int
37    {
38        if (!$now->isAfter($due)) {
39            return 0;
40        }
41
42        return intdiv($now->toMicroseconds() - $due->toMicroseconds(), $this->period->toMicroseconds());
43    }
44
45    public function describe(): string
46    {
47        return 'every ' . $this->period->__toString();
48    }
49
50    public function isRecurring(): bool
51    {
52        return true;
53    }
54}