Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
FrozenClock
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
3 / 3
8
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
5
 now
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fromTimestamp
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5/**
6 * This file is part of php-fast-forward/clock.
7 *
8 * This source file is subject to the license bundled
9 * with this source code in the file LICENSE.
10 *
11 * @copyright Copyright (c) 2025-2026 Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
12 * @license   https://opensource.org/licenses/MIT MIT License
13 *
14 * @see       https://github.com/php-fast-forward/clock
15 * @see       https://github.com/php-fast-forward
16 * @see       https://datatracker.ietf.org/doc/html/rfc2119
17 */
18
19namespace FastForward\Clock;
20
21use InvalidArgumentException;
22use DateTimeImmutable;
23use DateTimeInterface;
24use DateTimeZone;
25use Psr\Clock\ClockInterface;
26
27/**
28 * Provides the current system time in a predictable timezone.
29 */
30  class FrozenClock implements ClockInterface
31{
32    private DateTimeImmutable $now;
33
34    /**
35     * Creates a new frozen clock.
36     *
37     * @param DateTimeInterface|ClockInterface|string|int|float $clock the time to freeze, or a ClockInterface to use its current time
38     */
39    public function __construct(DateTimeInterface|ClockInterface|string|int|float $clock = 'now')
40    {
41        if ($clock instanceof ClockInterface) {
42            $clock = $clock->now();
43        }
44
45        if (\is_int($clock) || \is_float($clock)) {
46            $clock = $this->fromTimestamp($clock);
47        }
48
49        $this->now = $clock instanceof DateTimeInterface
50            ? DateTimeImmutable::createFromInterface($clock)
51            : new DateTimeImmutable($clock);
52    }
53
54    /**
55     * Returns the current date-time.
56     */
57    public function now(): DateTimeImmutable
58    {
59        return $this->now;
60    }
61
62    /**
63     * @param float|int $timestamp
64     *
65     * @return DateTimeImmutable
66     *
67     * @throws InvalidArgumentException
68     */
69    private function fromTimestamp(float|int $timestamp): DateTimeImmutable
70    {
71        $dateTime = DateTimeImmutable::createFromFormat(
72            'U.u',
73            \sprintf('%.6F', $timestamp),
74            new DateTimeZone('UTC'),
75        );
76
77        if (false === $dateTime) {
78            throw new InvalidArgumentException('Invalid timestamp.');
79        }
80
81        return $dateTime->setTimezone(new DateTimeZone(date_default_timezone_get()));
82    }
83}