Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Clock Laravel Package

lcobucci/clock

Small PHP clock abstraction to decouple your code from direct DateTimeImmutable instantiation. Depend on the Clock interface and use SystemClock for real time or FrozenClock for deterministic tests, with explicit timezone support.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:
    composer require lcobucci/clock
    
  2. Basic Usage: Inject the Clock interface into your services:
    use Lcobucci\Clock\Clock;
    use Lcobucci\Clock\SystemClock;
    
    class MyService {
        public function __construct(private Clock $clock) {}
    }
    
  3. Register in Laravel: Bind the Clock interface in AppServiceProvider:
    public function register(): void {
        $this->app->bind(Clock::class, function () {
            return new SystemClock(new DateTimeZone('UTC'));
        });
    }
    

First Use Case

Replace new DateTimeImmutable() calls with $clock->now() in:

  • Time-sensitive logic (e.g., expiration checks, rate limiting).
  • Testing (use FrozenClock to mock time).

Implementation Patterns

Dependency Injection

  1. Service Container Binding:

    // For production (UTC)
    $this->app->singleton(Clock::class, fn() => SystemClock::fromUTC());
    
    // For testing (frozen time)
    $this->app->when(TestCase::class)
        ->needs(Clock::class)
        ->give(FrozenClock::fromUTC());
    
  2. Constructor Injection:

    class OrderService {
        public function __construct(
            private Clock $clock,
            private OrderRepository $orders
        ) {}
    
        public function cancelExpiredOrders(): void {
            $now = $clock->now();
            $this->orders->cancelWhere('expires_at < ?', $now);
        }
    }
    

Testing Workflows

  1. Frozen Time for Tests:

    $clock = new FrozenClock(new DateTimeImmutable('2023-01-01'));
    $this->app->instance(Clock::class, $clock);
    
    // Advance time in tests
    $clock->adjustTime(new DateTimeImmutable('2023-01-02'));
    
  2. Time-Based Assertions:

    $this->assertEquals(
        new DateTimeImmutable('2023-01-01'),
        $clock->now()
    );
    

Integration Tips

  1. Laravel Tasks: Use SystemClock for scheduled jobs (e.g., app(Clock::class)->now() in job handlers).
  2. API Responses: Attach timestamps using $clock->now() for consistency:
    return response()->json([
        'created_at' => $clock->now()->format(DateTimeInterface::ATOM),
    ]);
    

Gotchas and Tips

Pitfalls

  1. Timezone Mismatches:

    • Always explicitly set the timezone in SystemClock (e.g., SystemClock::fromUTC()).
    • Avoid relying on the system’s default timezone.
  2. Immutable SystemClock:

    • The SystemClock is marked as @immutable in PHP 8.3+. Avoid modifying it after creation.
  3. Thread Safety:

    • SystemClock is thread-safe, but FrozenClock is not. Use FrozenClock only in single-threaded contexts (e.g., tests).

Debugging

  1. Time Drift in Tests:

    • If tests fail due to time adjustments, ensure FrozenClock is properly reset between tests:
    $this->app->forgetInstance(Clock::class);
    
  2. Performance:

    • SystemClock::now() is lightweight, but avoid calling it in tight loops. Cache results if needed.

Extension Points

  1. Custom Clock Implementations:

    class DatabaseClock implements Clock {
        public function now(): DateTimeInterface {
            return new DateTimeImmutable(
                DB::table('clock')->value('current_time')
            );
        }
    }
    
  2. Time Adjustment:

    • Use FrozenClock::adjustTime() for time-traveling tests:
    $clock->adjustTime(new DateTimeImmutable('+1 hour'));
    
  3. PSR-20 Compliance:

    • The package implements PSR\Clock\ClockInterface. Prefer this interface for future-proofing:
    use PSR\Clock\ClockInterface;
    

Laravel-Specific Tips

  1. Configurable Timezone: Add a config option in config/app.php:

    'timezone' => env('APP_TIMEZONE', 'UTC'),
    

    Then bind dynamically:

    $this->app->singleton(Clock::class, fn() =>
        SystemClock::from(new DateTimeZone(config('app.timezone')))
    );
    
  2. Testing Helpers: Create a test trait for frozen clocks:

    trait UsesFrozenClock {
        protected function freezeTime(string $time = 'now'): FrozenClock {
            return $this->app->instance(
                Clock::class,
                $time === 'now'
                    ? FrozenClock::fromUTC()
                    : new FrozenClock(new DateTimeImmutable($time))
            );
        }
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai