Lines
100.00%
11 / 11
Methods
100.00%
9 / 9
Classes
100.00%
1 / 1
| Name | Lines | Methods | CRAP | ||||
|---|---|---|---|---|---|---|---|
| __construct | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 1 | ||
| getNow | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| getMonotonicTime | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| getTimeZone | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| isWithin | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| getWallTime | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| moveTo | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| skip | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| rewind | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| 16 | final class VirtualClock implements Clock | |
| 17 | { | |
| 18 | private const string DEFAULT_START = '2026-01-01 00:00:00 UTC'; | |
| 19 | ||
| 20 | private readonly int $startMicroseconds; | |
| 21 | ||
| 22 | private readonly DateTimeZone $zone; | |
| 23 | ||
| 24 | private int $elapsedMicroseconds = 0; | |
| 25 | ||
| 26 | private int $skewMicroseconds = 0; | |
| 27 | ||
| 28 | public function __construct(?DateTimeImmutable $start = null) | |
| 29 | { | |
| 30 | $start ??= new DateTimeImmutable(self::DEFAULT_START); | |
| 31 | ||
| 32 | $this->startMicroseconds = Instant::fromDateTime($start)->toEpochMicroseconds(); | |
| 33 | $this->zone = $start->getTimezone(); | |
| 34 | } | |
| 35 | ||
| 36 | public function getNow(): Instant | |
| 37 | { | |
| 38 | return Instant::fromEpochMicroseconds($this->startMicroseconds + $this->elapsedMicroseconds + $this->skewMicroseconds); | |
| 39 | } | |
| 40 | ||
| 41 | public function getMonotonicTime(): MonotonicTime | |
| 42 | { | |
| 43 | return MonotonicTime::fromMicroseconds($this->elapsedMicroseconds); | |
| 44 | } | |
| 45 | ||
| 46 | public function getTimeZone(): DateTimeZone | |
| 47 | { | |
| 48 | return $this->zone; | |
| 49 | } | |
| 50 | ||
| 51 | public function isWithin(TimeOfDay|string $start, TimeOfDay|string $end): bool | |
| 52 | { | |
| 53 | return TimeWindow::between($start, $end)->includes($this->getNow()->toDateTime($this->getTimeZone())); | |
| 54 | } | |
| 55 | ||
| 56 | public function getWallTime(): DateTimeImmutable | |
| 57 | { | |
| 58 | return $this->getNow()->toDateTime($this->zone); | |
| 59 | } | |
| 60 | ||
| 61 | public function moveTo(MonotonicTime $moment): void | |
| 62 | { | |
| 63 | $this->elapsedMicroseconds = max($this->elapsedMicroseconds, $moment->toMicroseconds()); | |
| 64 | } | |
| 65 | ||
| 66 | public function skip(Duration $by): void | |
| 67 | { | |
| 68 | $this->skewMicroseconds += $by->toMicroseconds(); | |
| 69 | } | |
| 70 | ||
| 71 | public function rewind(Duration $by): void | |
| 72 | { | |
| 73 | $this->skewMicroseconds -= $by->toMicroseconds(); | |
| 74 | } | |
| 75 | } |