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

symfony/clock

Symfony Clock decouples your app from the system clock via a ClockInterface. Swap real and test clocks, get DateTimeImmutable “now()” values, control time zones, and pause execution with sleep()—ideal for time-sensitive code and reliable testing.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require symfony/clock
    

    No additional configuration is required for basic usage.

  2. First Use Case: Replace direct system time calls (e.g., time(), Carbon::now()) with dependency-injected ClockInterface. Example:

    use Symfony\Component\Clock\NativeClock;
    use Symfony\Component\Clock\ClockInterface;
    
    class SubscriptionService {
        public function __construct(private ClockInterface $clock) {}
    
        public function isExpired(\DateTimeImmutable $subscriptionDate): bool {
            return $this->clock->now() > $subscriptionDate;
        }
    }
    
  3. Register the Clock in Laravel: Bind NativeClock in a service provider (e.g., AppServiceProvider):

    use Symfony\Component\Clock\NativeClock;
    
    public function register() {
        $this->app->singleton(ClockInterface::class, fn() => new NativeClock());
    }
    
  4. First Test Case: Use MockClock to freeze time in unit tests:

    use Symfony\Component\Clock\MockClock;
    
    public function testSubscriptionExpiry() {
        $clock = new MockClock(new \DateTimeImmutable('2023-01-01'));
        $service = new SubscriptionService($clock);
    
        $this->assertFalse($service->isExpired(new \DateTimeImmutable('2024-01-01')));
    }
    

Where to Look First


Implementation Patterns

Core Workflows

1. Dependency Injection Pattern

  • Production: Inject NativeClock (default system time).
    $this->app->bind(ClockInterface::class, fn() => new NativeClock());
    
  • Testing: Inject MockClock for deterministic time.
    $clock = new MockClock(new \DateTimeImmutable('2023-01-01'));
    $this->app->instance(ClockInterface::class, $clock);
    
  • Custom Logic: Inject a custom clock (e.g., RedisClock for distributed time sync).
    $this->app->bind(ClockInterface::class, fn() => new RedisClock());
    

2. Timezone Isolation

  • Force a timezone for all time operations:
    $clock = (new NativeClock())->withTimeZone('UTC');
    $this->app->instance(ClockInterface::class, $clock);
    
  • Useful for:
    • Multi-region Laravel apps.
    • APIs serving global users (e.g., "Your session expires in 10 minutes" in UTC).

3. Time-Aware Delays

  • Replace sleep() or usleep() with clock-aware pauses:
    // In a background job or command
    $this->clock->sleep(2.5); // Pauses for 2.5 seconds
    
  • Why? Avoids race conditions in tests (e.g., sleep(1) may run faster/slower in CI).
  • Gotcha: sleep() throws \InvalidArgumentException for negative values (use MockClock for time rewinding).

4. Stopwatch for Benchmarking

  • Measure durations without system clock interference:
    $stopwatch = $this->clock->stopwatch();
    $stopwatch->start('process_order');
    
    // ... business logic ...
    
    $duration = $stopwatch->lap('process_order'); // Returns \DateInterval
    

5. Laravel-Specific Patterns

  • ClockSensitiveTrait: Auto-injects ClockInterface (Laravel 10+):
    use Illuminate\Clock\ClockSensitive;
    
    class MyService {
        use ClockSensitive;
    
        public function doWork() {
            $now = $this->clock->now();
            // ...
        }
    }
    
  • Testing Helpers: Use Laravel’s travel() alongside MockClock:
    use Illuminate\Testing\Concerns\InteractsWithTime;
    
    public function testTimeTravel() {
        $clock = new MockClock(new \DateTimeImmutable('2023-01-01'));
        $this->app->instance(ClockInterface::class, $clock);
    
        // Now use Laravel's travel() for Carbon compatibility
        Carbon::setTestNow($clock->now());
    }
    

Integration Tips

With Laravel Queues

  • Replace sleep() in jobs with $this->clock->sleep() for deterministic delays:
    public function handle() {
        $this->clock->sleep(5); // 5-second delay
        // ...
    }
    
  • Test Tip: Use MockClock to fast-forward job processing:
    $clock = new MockClock(new \DateTimeImmutable('2023-01-01 00:00:10'));
    $this->app->instance(ClockInterface::class, $clock);
    

With Events

  • Dispatch time-sensitive events with controlled clocks:
    $clock = new MockClock(new \DateTimeImmutable('2023-01-01 12:00:00'));
    event(new OrderPlaced($order, $clock->now()));
    
  • Use Case: Test event listeners that react to time (e.g., "send reminder after 24 hours").

With Database Timestamps

  • Use ClockInterface to generate timestamps for Eloquent models:
    $model = new Post();
    $model->created_at = $this->clock->now();
    
  • Why? Ensures consistency with your app’s clock (e.g., avoid now() vs. freshTimestamp() mismatches).

With API Clients

  • Simulate API rate limits or timeouts:
    $clock = new MockClock(new \DateTimeImmutable('2023-01-01 10:00:00'));
    $response = $this->client->get('/api/rate-limited-endpoint', [
        'clock' => $clock,
    ]);
    

With Feature Flags

  • Time-based flags become testable:
    class FeatureFlagService {
        public function isEnabled(string $flagName): bool {
            $now = $this->clock->now();
            $flag = Flag::where('name', $flagName)
                ->where('starts_at', '<=', $now)
                ->where('ends_at', '>=', $now)
                ->first();
    
            return $flag !== null;
        }
    }
    
  • Test Example:
    $clock = new MockClock(new \DateTimeImmutable('2023-01-01 14:00:00'));
    $this->assertTrue($service->isEnabled('new_checkout_flow'));
    

Gotchas and Tips

Pitfalls

  1. Negative sleep() Values

    • NativeClock::sleep(-1) throws \InvalidArgumentException.
    • Workaround: Use MockClock to rewind time:
      $clock = new MockClock(new \DateTimeImmutable('2023-01-01 10:00:00'));
      $clock->sleep(-5); // Rewinds 5 seconds (allowed in MockClock)
      
  2. Timezone Mismatches

    • withTimeZone() does not modify the DateTimeImmutable’s timezone retroactively. Always set it upfront:
      // Wrong: Assumes UTC after setting timezone
      $clock = new NativeClock();
      $now = $clock->now(); // System timezone
      $clock = $clock->withTimeZone('UTC'); // Too late!
      
      // Correct:
      $clock = (new NativeClock())->withTimeZone('UTC');
      
  3. Immutable DateTimeImmutable

    • Modifying the returned DateTimeImmutable (e.g., $now->modify('+1 day')) does not affect the clock’s state. Clocks are stateless:
      $now = $this->clock->now();
      $now->modify('+1 day'); // Only affects $now, not future calls to $this->clock->now()
      
  4. MockClock Precision

    • MockClock advances time in second increments by default. For microsecond precision
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