acc-create-psr20-clock
Generates PSR-20 Clock implementation for PHP 8.5. Creates ClockInterface implementations including SystemClock, FrozenClock, and OffsetClock for time abstraction and testing. Includes unit tests.
Best use case
acc-create-psr20-clock is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Generates PSR-20 Clock implementation for PHP 8.5. Creates ClockInterface implementations including SystemClock, FrozenClock, and OffsetClock for time abstraction and testing. Includes unit tests.
Teams using acc-create-psr20-clock should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/acc-create-psr20-clock/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How acc-create-psr20-clock Compares
| Feature / Agent | acc-create-psr20-clock | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Generates PSR-20 Clock implementation for PHP 8.5. Creates ClockInterface implementations including SystemClock, FrozenClock, and OffsetClock for time abstraction and testing. Includes unit tests.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# PSR-20 Clock Generator
## Overview
Generates PSR-20 compliant clock implementations for time abstraction.
## When to Use
- Time-dependent business logic
- Testing time-sensitive code
- Scheduling and time calculations
- Reproducible time behavior
## Template: Clock Interface
```php
<?php
declare(strict_types=1);
namespace App\Infrastructure\Clock;
use DateTimeImmutable;
interface ClockInterface
{
public function now(): DateTimeImmutable;
}
```
## Template: System Clock
```php
<?php
declare(strict_types=1);
namespace App\Infrastructure\Clock;
use DateTimeImmutable;
use Psr\Clock\ClockInterface;
final readonly class SystemClock implements ClockInterface
{
public function __construct(
private ?string $timezone = null,
) {
}
public function now(): DateTimeImmutable
{
$now = new DateTimeImmutable('now');
if ($this->timezone !== null) {
return $now->setTimezone(new \DateTimeZone($this->timezone));
}
return $now;
}
}
```
## Template: Frozen Clock (Testing)
```php
<?php
declare(strict_types=1);
namespace App\Infrastructure\Clock;
use DateTimeImmutable;
use Psr\Clock\ClockInterface;
final class FrozenClock implements ClockInterface
{
public function __construct(
private DateTimeImmutable $frozenAt,
) {
}
public function now(): DateTimeImmutable
{
return $this->frozenAt;
}
public function setTo(DateTimeImmutable $dateTime): void
{
$this->frozenAt = $dateTime;
}
public static function at(string $datetime): self
{
return new self(new DateTimeImmutable($datetime));
}
public static function fromTimestamp(int $timestamp): self
{
return new self((new DateTimeImmutable())->setTimestamp($timestamp));
}
}
```
## Template: Offset Clock
```php
<?php
declare(strict_types=1);
namespace App\Infrastructure\Clock;
use DateInterval;
use DateTimeImmutable;
use Psr\Clock\ClockInterface;
final readonly class OffsetClock implements ClockInterface
{
public function __construct(
private ClockInterface $baseClock,
private DateInterval $offset,
private bool $subtract = false,
) {
}
public function now(): DateTimeImmutable
{
$now = $this->baseClock->now();
return $this->subtract
? $now->sub($this->offset)
: $now->add($this->offset);
}
public static function ahead(ClockInterface $clock, DateInterval $offset): self
{
return new self($clock, $offset, false);
}
public static function behind(ClockInterface $clock, DateInterval $offset): self
{
return new self($clock, $offset, true);
}
public static function daysAhead(ClockInterface $clock, int $days): self
{
return new self($clock, new DateInterval("P{$days}D"), false);
}
public static function daysBehind(ClockInterface $clock, int $days): self
{
return new self($clock, new DateInterval("P{$days}D"), true);
}
}
```
## Template: Monotonic Clock
```php
<?php
declare(strict_types=1);
namespace App\Infrastructure\Clock;
use DateTimeImmutable;
use Psr\Clock\ClockInterface;
final class MonotonicClock implements ClockInterface
{
private ?DateTimeImmutable $lastTime = null;
public function __construct(
private readonly ClockInterface $baseClock,
) {
}
public function now(): DateTimeImmutable
{
$current = $this->baseClock->now();
if ($this->lastTime !== null && $current <= $this->lastTime) {
// Ensure time always moves forward
$current = $this->lastTime->modify('+1 microsecond');
}
$this->lastTime = $current;
return $current;
}
}
```
## Template: Unit Test
```php
<?php
declare(strict_types=1);
namespace App\Tests\Unit\Infrastructure\Clock;
use App\Infrastructure\Clock\FrozenClock;
use App\Infrastructure\Clock\OffsetClock;
use App\Infrastructure\Clock\SystemClock;
use DateInterval;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
#[Group('unit')]
#[CoversClass(SystemClock::class)]
#[CoversClass(FrozenClock::class)]
#[CoversClass(OffsetClock::class)]
final class ClockTest extends TestCase
{
public function test_system_clock_returns_current_time(): void
{
$clock = new SystemClock();
$before = new DateTimeImmutable();
$now = $clock->now();
$after = new DateTimeImmutable();
self::assertGreaterThanOrEqual($before, $now);
self::assertLessThanOrEqual($after, $now);
}
public function test_system_clock_with_timezone(): void
{
$clock = new SystemClock('UTC');
$now = $clock->now();
self::assertSame('UTC', $now->getTimezone()->getName());
}
public function test_frozen_clock_returns_fixed_time(): void
{
$frozenTime = new DateTimeImmutable('2024-01-15 10:30:00');
$clock = new FrozenClock($frozenTime);
self::assertEquals($frozenTime, $clock->now());
self::assertEquals($frozenTime, $clock->now());
}
public function test_frozen_clock_can_be_updated(): void
{
$clock = FrozenClock::at('2024-01-15 10:30:00');
$newTime = new DateTimeImmutable('2024-06-01 12:00:00');
$clock->setTo($newTime);
self::assertEquals($newTime, $clock->now());
}
public function test_offset_clock_adds_time(): void
{
$baseClock = FrozenClock::at('2024-01-15 10:30:00');
$clock = OffsetClock::daysAhead($baseClock, 5);
$expected = new DateTimeImmutable('2024-01-20 10:30:00');
self::assertEquals($expected, $clock->now());
}
public function test_offset_clock_subtracts_time(): void
{
$baseClock = FrozenClock::at('2024-01-15 10:30:00');
$clock = OffsetClock::daysBehind($baseClock, 5);
$expected = new DateTimeImmutable('2024-01-10 10:30:00');
self::assertEquals($expected, $clock->now());
}
}
```
## Usage Example
```php
<?php
use App\Infrastructure\Clock\FrozenClock;
use App\Infrastructure\Clock\SystemClock;
// Production: Use system clock
$clock = new SystemClock('UTC');
$service = new SubscriptionService($clock);
// Testing: Use frozen clock
$clock = FrozenClock::at('2024-01-15 10:30:00');
$service = new SubscriptionService($clock);
// Service using clock
final readonly class SubscriptionService
{
public function __construct(
private ClockInterface $clock,
) {
}
public function isExpired(Subscription $subscription): bool
{
return $subscription->expiresAt() < $this->clock->now();
}
public function daysUntilExpiry(Subscription $subscription): int
{
$diff = $this->clock->now()->diff($subscription->expiresAt());
return $diff->invert ? 0 : $diff->days;
}
}
```
## File Placement
| Component | Path |
|-----------|------|
| Clock Interface | `src/Infrastructure/Clock/ClockInterface.php` |
| System Clock | `src/Infrastructure/Clock/SystemClock.php` |
| Frozen Clock | `src/Infrastructure/Clock/FrozenClock.php` |
| Offset Clock | `src/Infrastructure/Clock/OffsetClock.php` |
| Monotonic Clock | `src/Infrastructure/Clock/MonotonicClock.php` |
| Tests | `tests/Unit/Infrastructure/Clock/` |
## Requirements
```json
{
"require": {
"psr/clock": "^1.0"
}
}
```Related Skills
acc-create-value-object
Generates DDD Value Objects for PHP 8.5. Creates immutable, self-validating objects with equality comparison. Includes unit tests.
acc-create-use-case
Generates Application Use Cases for PHP 8.5. Creates orchestration services that coordinate domain objects, handle transactions, and dispatch events. Includes unit tests.
acc-create-unit-test
Generates PHPUnit unit tests for PHP 8.5. Creates isolated tests with AAA pattern, proper naming, attributes, and one behavior per test. Supports Value Objects, Entities, Services.
acc-create-test-double
Generates test doubles (Mocks, Stubs, Fakes, Spies) for PHP 8.5. Creates appropriate double type based on testing needs with PHPUnit MockBuilder patterns.
acc-create-test-builder
Generates Test Data Builder and Object Mother patterns for PHP 8.5. Creates fluent builders with sensible defaults and factory methods for test data creation.
acc-create-strategy
Generates Strategy pattern for PHP 8.5. Creates interchangeable algorithm families with context class, strategy interface, and concrete implementations. Includes unit tests.
acc-create-state
Generates State pattern for PHP 8.5. Creates state machines with context, state interface, and concrete states for behavior changes. Includes unit tests.
acc-create-specification
Generates DDD Specification for PHP 8.5. Creates reusable business rule objects for validation, filtering, and querying with composite pattern support. Includes unit tests.
acc-create-saga-pattern
Generates Saga pattern components for PHP 8.5. Creates Saga interfaces, steps, orchestrator, state management, and compensation logic with unit tests.
acc-create-retry-pattern
Generates Retry pattern for PHP 8.5. Creates resilience component with exponential backoff, jitter, and configurable retry strategies. Includes unit tests.
acc-create-responder
Generates ADR Responder classes for PHP 8.5. Creates HTTP response builders with PSR-7/PSR-17 support. Includes unit tests.
acc-create-repository
Generates DDD Repository interfaces and implementation stubs for PHP 8.5. Creates domain interfaces in Domain layer, implementation in Infrastructure.