Weave 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

tempest/clock

A lightweight clock abstraction for the Tempest framework, offering a testable interface for reading the current time. Swap in a frozen or mock clock during tests so time-dependent code stays deterministic instead of relying on native PHP date functions.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Verdict: Do not adopt as a dependency. Adopt the pattern, not the package. The capability is worth having; this specific distribution is not a viable dependency for a Laravel application at this maturity level.

Architecture fit

tempest/clock is a first-party component of the Tempest PHP framework, not a Laravel package. There is no ServiceProvider, no extra.laravel auto-discovery block, no facade, no publishable config, and no Laravel-facing contract. Its design assumptions are Tempest's: constructor-injection through the Tempest container, discovery-based wiring, and sibling tempest/* packages. In a Laravel application it is an unmanaged library at best.

The underlying concept — an injectable Clock boundary so that now(), sleep(), and elapsed-time logic are deterministic under test — fits Laravel extremely well. But Laravel already has three overlapping solutions in-tree or transitively:

  • Carbon::setTestNow() / Carbon::withTestNow() (the idiomatic path for the last decade, and what most Laravel test suites already use)
  • symfony/clock + PSR-20 ClockInterface, which is present transitively in virtually every Laravel install via the Symfony console/HTTP stack
  • Illuminate\Support\Facades\Date, which fronts Carbon for app-level overrides

So this package competes with an interface that is already on the classpath, already PSR-standardized, and already familiar to the team.

Integration feasibility

Two viable paths, in order of preference:

  1. Pattern transplant (recommended). Read the source — it is a small, readable component — and reimplement the interface inside the app in roughly 50–150 LOC against Psr\Clock\ClockInterface, with a SystemClock and a FrozenClock/MockClock for tests. This yields a Laravel-native service provider, full control of the contract, no third-party ownership of a cross-cutting concern, and no Tempest transitive dependencies.
  2. Adapter (only after source verification). Bind the package's Clock into Laravel's container via a thin provider and alias the interface. This succeeds only if the component is genuinely standalone. If it pulls in tempest/support or the Tempest container contracts, path 2 collapses into vendoring a foreign framework's kernel, which is a hard no.

Technical risk: HIGH

Dimension Assessment
Adoption 0 stars, 0 dependents, no downstream usage to learn from
Maturity Pre-1.0; no documented semver support window
Bus factor Effectively 1 (Tempest core team); no external contributors of record
Security No published security policy; no CVE history to extrapolate from
Supply chain Small surface area, but unmonitored — no dependabot signal, no advisory feed
Lock-in Bidirectional: adopting it couples your time abstraction to a framework you do not use

The risk is not that the code is bad — it is that a cross-cutting, every-request-executed abstraction is being sourced from a zero-adoption package. That is a poor risk/reward trade for something the platform can express in a few lines.

Key questions (must be answered before any commitment)

  1. Does the package declare a hard dependency on tempest/support or Tempest container contracts? (composer show --tree tempest/clock)
  2. Does it implement Psr\Clock\ClockInterface, or a bespoke interface? A PSR implementation is portable; a bespoke one is not.
  3. What is the API surface — now(), sleep(), time(), timezone handling, monotonic vs. wall-clock semantics?
  4. Is the clock mutable/freezable for tests, and is there a documented reset between tests?
  5. What PHP versions and what Tempest version does it target, and how frequently does it ship breaking changes?
  6. Is there any commit activity in the last 6 months, and is there a maintainer-stated stability commitment?
  7. What is the license interaction — MIT is compatible, but is there a CLA or attribution obligation for copied source in a transplant?

Integration Approach

Stack fit

Laravel 10/11/12 on PHP 8.2+. The recommended shape is a single Clock binding in a TimeServiceProvider aliasing Psr\Clock\ClockInterface to a SystemClock in production and a FrozenClock in tests. Consumers type-hint the interface; nothing calls now(), time(), date(), microtime(), or Carbon::now() directly in domain code. That is the entire architectural commitment — roughly one provider, one interface, two implementations.

Migration path

Phased and reversible, with no user-facing behavior change:

  1. Spike (0.5 day) — resolve the package, inspect composer show --tree, confirm standalone-ness, and diff its API against Psr\Clock\ClockInterface. Decision gate: if it drags Tempest contracts in, stop and go to step 2b.
  2. 2a. Transplant — vendor the pattern (not the code, absent license review) into app/Support/Clock/. Two implementations, one provider, one test fake. 2b. Adapter — only if the spike proves standalone: composer require tempest/clock with an exact version pin and a provide-style alias binding in a Laravel provider.
  3. Retrofit — convert time reads in the highest-value seam first (billing, scheduling, TTL/expiry logic, idempotency windows), not application-wide. Leave Carbon::now() in presentation and logging layers.
  4. Test-suite alignment — codify a base TestCase that freezes the clock and asserts determinism on a small set of flaky-history tests.

Compatibility

  • Coexists cleanly with Carbon::setTestNow() if the FrozenClock is implemented on top of Carbon, so both mechanisms agree and the team does not get two divergent notions of "now."
  • symfony/clock is likely already installed; prefer binding to Psr\Clock\ClockInterface so either implementation satisfies the contract, keeping the adapter reversible.
  • Watch for timezone divergence: a package-native clock may default to UTC while the app's config('app.timezone') is something else. Normalize at the boundary; store UTC, render local.
  • If tempest/clock requires a PHP or Tempest version outside the app's constraint, Composer will either refuse or silently downgrade a shared dependency — pin exactly and run composer why-not before merging.

Sequencing

Spike → interface decision (PSR vs. bespoke) → binding + provider → one pilot seam → test base class → expand. Do not block any roadmap item on this; it is a background quality investment sized at ~3–5 engineer-days end to end, most of which is retrofit and tests, not plumbing.


Operational Impact

Maintenance

Under the transplant path, ownership is internal and the footprint is small enough that any Laravel engineer can maintain it — this is the whole argument for transplanting. Under the dependency path, you inherit an external release cadence you do not control for a component that executes on every request, with no dependents to surface breakage before you do. Upgrades become a manual, low-signal chore. Mitigation if the dependency is taken anyway: exact version pin, a composer outdated check in CI, and a documented 30-minute revert to an in-house implementation.

Support

There is no commercial support, no SLA, no documented support window, and effectively no community to ask. Escalation path is "read the source" — acceptable for a 200-line utility, not for something in the request hot path. Budget internal ownership explicitly rather than assuming upstream absorbs it.

Scaling

Runtime cost is negligible — a bound singleton returning a timestamp; no measurable throughput or memory impact at any realistic request volume. The scaling concern is organizational, not computational: the more call sites depend on the contract, the costlier a later contract change becomes. That argues for choosing the interface deliberately once (PSR-20) rather than letting a third party's signature dictate it.

Failure modes

  • Container resolution failure — interface bound but not aliased, or a package-internal Tempest container lookup that Laravel cannot satisfy. Manifests as a boot-time BindingResolutionException; caught immediately in CI, low severity.
  • Frozen clock leaking into production — the highest-severity failure. A test fake or a mis-scoped binding serving a static timestamp causes expired-token acceptance, duplicate idempotency keys, broken TTLs, and stalled schedulers. Mitigate with a SystemClock default bound in AppServiceProvider only, FrozenClock scoped to the test base class, and an assertion in the health check that "now" advances.
  • Timezone drift — UTC-default clock vs. app-local expectations producing off-by-hours logic in billing or scheduling. Mitigate by normalizing at the boundary.
  • Monotonic vs. wall clock confusion — using the abstraction for elapsed-time measurement where the system clock can jump (NTP correction, DST). Timeouts and retry budgets need a monotonic source; document which is which.
  • Silent abandonment upstream — the package stops receiving updates mid-major-version with the app pinned to it. Low blast radius given the size, but it converts an upgrade into a rewrite; the transplant path eliminates this failure mode entirely.

Ramp-up

Near-zero. The API surface is a handful of methods; a mid-level engineer is productive in under an hour, and the retrofit work is mechanical. The real ramp-up cost is cultural — getting the team to stop calling now() directly and to inject the boundary consistently, which requires lint/static-analysis enforcement (a PHPStan or Pint rule banning bare now()/time() in app/Domain) rather than documentation alone.

Bottom line for the roadmap: treat this as a 3–5 day internal quality initiative, not a dependency evaluation. Revisit tempest/clock only if Tempest reaches 1.0 with meaningful adoption and the package ships a PSR-20 implementation with no Tempest kernel coupling. Until then, an in-house Clock bound to Psr\Clock\ClockInterface delivers the same value at strictly lower risk.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource