FrozenClock
FastForward\Clock\FrozenClock
provides a fixed, deterministic time ideal for testing scenarios.
Description
This class implements Psr\Clock\ClockInterface
and returns a fixed time regardless of when it's called.
This makes it perfect for writing reliable tests where time-dependent behavior needs to be predictable.
Unlike SystemClock
which returns the current time, FrozenClock
always returns the time that was
set when the clock was created.
Constructor
public function __construct(DateTimeInterface|ClockInterface|string|int|float $clock = 'now')
Parameters
-
$clock(DateTimeInterface|ClockInterface|string|int|float): The time to freeze. Defaults to'now'.Supported formats:
DateTimeInterface: Any DateTimeImmutable or DateTime objectClockInterface: Another PSR-20 clock implementation (its current time is used)string: Relative or absolute date strings (e.g.,'2026-04-07 10:00:00','next Monday')int: Unix timestampfloat: Unix timestamp with microseconds
Methods
now()
Returns the frozen date-time as DateTimeImmutable
.
public function now(): DateTimeImmutable
Usage examples
Basic usage with string:
<?php
declare(strict_types=1);
use FastForward\Clock\FrozenClock;
$clock = new FrozenClock('2026-04-07 10:00:00');
echo $clock->now()->format(DATE_ATOM) . PHP_EOL;
// Output: 2026-04-07T10:00:00+00:00
With DateTimeImmutable:
<?php
declare(strict_types=1);
use FastForward\Clock\FrozenClock;
$frozenTime = new DateTimeImmutable('2026-04-07 10:00:00', new DateTimeZone('America/Sao_Paulo'));
$clock = new FrozenClock($frozenTime);
echo $clock->now()->format(DATE_ATOM) . PHP_EOL;
With timestamp:
<?php
declare(strict_types=1);
use FastForward\Clock\FrozenClock;
$clock = new FrozenClock(1775640000); // 2026-04-07 10:00:00 UTC
echo $clock->now()->format(DATE_ATOM) . PHP_EOL;
With another ClockInterface:
<?php
declare(strict_types=1);
use FastForward\Clock\FrozenClock;
use FastForward\Clock\SystemClock;
$clock = new FrozenClock(new SystemClock('America/New_York'));
echo $clock->now()->format(DATE_ATOM) . PHP_EOL;
With relative time strings:
<?php
declare(strict_types=1);
use FastForward\Clock\FrozenClock;
// Freeze to "one hour from now"
$clock = new FrozenClock('+1 hour');
// Freeze to "yesterday"
$clock = new FrozenClock('yesterday');
Testing example:
<?php
declare(strict_types=1);
use FastForward\Clock\FrozenClock;
final class TokenGenerator
{
public function __construct(private ClockInterface $clock)
{
}
public function expiresAt(int $ttlMinutes = 15): DateTimeImmutable
{
return $this->clock->now()->add(new DateInterval("PT{$ttlMinutes}M"));
}
}
// In your test
$frozenClock = new FrozenClock('2026-04-07 10:00:00');
$generator = new TokenGenerator($frozenClock);
$expiresAt = $generator->expiresAt(15);
// $expiresAt is always 2026-04-07T10:15:00+00:00, not dependent on when test runs
Notes
- This class is
final readonly, meaning it cannot be extended - The frozen time is set once during construction and never changes
- Useful for testing time-sensitive operations like token expiration, cache TTL, etc.
- Accepts any input that PHP's
DateTimeImmutablecan parse