- How do I install and use symfony/clock in a Laravel application?
- Install it with composer require symfony/clock, then bind the interface in a service provider, for example $this->app->bind(ClockInterface::class, NativeClock::class). Type-hint Symfony\Component\Clock\ClockInterface in the constructors of classes that need the current time and call $clock->now() to get a DateTimeImmutable. There is no config file, migration, or published asset, so integration is a single binding plus per-class constructor injection.
- How does symfony/clock MockClock compare to Carbon::setTestNow() in Laravel tests?
- Carbon::setTestNow() manipulates global static state, while MockClock is an injected instance you swap into the container for a specific test. Because the dependency is constructor-visible, you can see which classes depend on time and control it per test case rather than globally. The two are complementary: Carbon remains the standard for formatting and database timestamps, and the clock is the standard for domain time. Bind MockClock only inside the test scope, never in a provider gated on APP_ENV, or you freeze application time globally.
- Which PHP and Laravel versions does symfony/clock support?
- The 7.4 branch is the safe LTS target for most Laravel applications, while the 8.x line requires PHP 8.4 or newer and will exclude parts of many version matrices. If you use MockClock::sleep(), pin at or above 6.4.30 or 7.3.8, where a negative-value divergence was fixed. Check your PHP matrix before adopting 8.x, and prefer the 7.4 branch unless you already run PHP 8.4 everywhere.
- Should I type-hint Symfony\Component\Clock\ClockInterface or Psr\Clock\ClockInterface?
- The PSR-20 interface is more portable and survives a framework or component change, since psr/clock is a hard dependency of symfony/clock. Symfony's ClockInterface adds sleep() and withTimeZone(), which PSR-20 does not define. You can bind both in a service provider and alias one to the other, but pick one for your own domain classes so the codebase does not end up with multiple time idioms.
- How do I convert the value returned by ClockInterface::now() to a Carbon instance?
- now() returns a \DateTimeImmutable, so use CarbonImmutable::createFromInterface($clock->now()) to bridge into Laravel's existing date ecosystem. This keeps the clock abstraction in your domain layer while Carbon continues to handle formatting, comparisons, and Eloquent casts. The conversion is a one-liner and needs no adapter class.
- What is the difference between NativeClock and MonotonicClock in symfony/clock?
- NativeClock reads wall-clock time, which can jump due to NTP adjustments, DST changes, or VM suspend, so it should not be used to measure elapsed durations. MonotonicClock measures elapsed time and always moves forward, which makes it correct for retry backoff, timeouts, and rate-limit windows. Mixing the two in the same logic is a subtle bug class that is hard to reproduce, so choose deliberately per use case.
- How do I prevent MockClock from being bound in production?
- Bind NativeClock as the default ClockInterface implementation in a service provider and rebind MockClock only inside the test case itself, or through a trait like ClockSensitiveTrait scoped to tests. Never wrap the MockClock binding in an APP_ENV conditional, because a misconfigured environment variable would silently freeze application time everywhere. Treat the MockClock binding as test-only code that lives under the tests directory.
- Does symfony/clock replace Laravel's sleep facade or the travel() and freezeTime() test helpers?
- No. Laravel 11+ ships the Illuminate\Support\Sleep facade and its testing helpers are built into the framework, and symfony/clock competes for the same developer habit rather than replacing them outright. The architectural value it adds is the injectable interface, which is constructor-visible and swappable in production, not only under test. Adopt it for domain time and keep the framework helpers for what they already cover.
- Is symfony/clock a good fit for retry backoff and rate-limit windows in queued jobs?
- Yes, provided you use the right clock: MonotonicClock for measuring elapsed intervals and NativeClock for absolute deadlines and scheduling decisions. Injecting the clock also lets tests advance time without real sleeps, which makes queue job tests fast and deterministic. Note that MockClock::sleep() advances time instantly rather than blocking, which is exactly what you want in tests.
- Is symfony/clock worth adopting if only part of my codebase uses it?
- Partial adoption is the main risk: if only some classes read time through the clock, the rest can still flake in tests, and the abstraction costs more than it returns. Convert whole time-sensitive bounded contexts, such as trial expiry, renewal, or SLA logic, and assign someone to enforce that boundary. Its low dependent count on the split repository is a publishing artifact of Symfony's monorepo, so do not read it as a weak adoption signal either way.