kdyby/datetime-provider
Kdyby/DatetimeProvider is a Nette Framework extension that registers a DateTime provider service for obtaining the current date and time. Inject it instead of creating DateTime instances directly, making time-dependent code testable, mockable, and configurable via NEON configuration.
What the package actually does. Unchanged. kdyby/datetime-provider is a small Nette-ecosystem utility built around a single idea: instead of calling new \DateTime(), date(), or time() directly, application code asks an injected provider service for the current date, time, datetime, and timezone. That indirection lets tests freeze or offset "now" deterministically, and gives one consistent notion of the current instant across a request. The value is in the pattern, not the code — the implementation is a handful of classes wrapping \DateTimeImmutable plus a test/controllable variant, registered through a Nette DI compiler extension.
What v1.0.0 actually changes. The release notes contain one sentence — "first stable version" — and a link to documentation. There is no changelog, no feature list, no breaking-change notice, no deprecation list, no PHP support statement, and no license clarification. As of this review the Packagist/GitHub metadata was not re-pulled (the data payload supplied was empty), so star count, dependents, license classification, and the composer.json constraints must be treated as unverified rather than confirmed unchanged. Net effect: the release is a maturity signal, not an information event. It tells us a maintainer is still reachable and has chosen to commit to a semver-stable API. It does not address — and the notes give no basis to assume it addresses — a single one of the material objections below.
Architecture fit — still poor for a Laravel codebase. The package remains a Nette CompilerExtension package. Laravel has no automatic path to register or resolve these services; adoption requires hand-written service-provider bindings and, in practice, replacing the Nette extension with your own wiring. At that point you are using maybe 60–100 lines of vendor code and rewriting most of the integration surface. A 1.0.0 tag does not build a bridge.
Integration feasibility — technically easy, strategically pointless. Unchanged. Installing it pulls nette/di (and likely nette/utils) into a Laravel application, importing a second, unrelated DI container and its version constraints into your dependency graph for no benefit. More importantly, the package's only real selling point is already native to the stack: Laravel ships Illuminate\Support\Carbon::setTestNow(), plus travel(), travelTo(), and freezeTime() in the test case, and Carbon's setTestNow() covers the frozen-clock case globally. There is no capability gap to close.
If the 1.0.0 release did anything useful, it is most likely a composer.json modernization (PHP constraint bump alone). That is a precondition for adoption, not a reason for it — it lowers the cost of the option we have already declined.
Technical risk — high for the size of the prize.
php and nette/* constraints to admit 8.1–8.4 is exactly what the release note does not say. Assume nothing until the tag's composer.json is read.NOASSERTION meant GitHub/Packagist could not classify the license. Nothing in the release note indicates a LICENSE change or a license field added to composer.json. Until a human reads the LICENSE file at the v1.0.0 tag and legal signs off, treat it as all-rights-reserved — no redistribution, no vendoring into a proprietary repo. A version tag cannot grant rights.Key questions to resolve before any decision.
composer.json, not the release note. Specifically: PHP constraint, nette/* constraints, namespace/API breaks, and whether the license field was set.Recommendation: still do not adopt. The release is a genuine but non-decisive data point: it removes "abandoned" from the objection list and leaves "unattested." The license ambiguity, the foreign DI container, and the redundancy with native Laravel/Carbon and PSR-20 are all untouched. Reimplement the interface, or adopt PSR-20 (Psr\Clock\ClockInterface + symfony/clock) and bind it in AppServiceProvider. Re-open this assessment only if all three of the following land: a resolvable OSI license at v1.0.0, verified PHP 8.1+ support without forking, and evidence of at least one external production dependent. Until then this is a reimplementation-with-inspiration exercise, and a 1.0.0 tag on code you were going to rewrite is worth roughly nothing.
Stack fit. Still effectively none out of the box: Nette package, Laravel target, no bridge. Treat any adoption as a reimplementation with inspiration, not an integration. The 1.0.0 documentation link is worth skimming for the semantic contract (what "current date" vs "current datetime" vs "current timezone" mean, and how the controllable variant is intended to be driven), then discard the code path.
Migration path (recommended).
Psr\Clock\ClockInterface (now(): DateTimeImmutable) plus your own TimeProvider interface if you need getCurrentDate() / getCurrentTime() / getCurrentTimezone() parity with the Kdyby shape.SystemClock (production, wraps Symfony\Component\Clock\Clock) and FrozenClock (tests, explicit instant, immutable).AppServiceProvider: SystemClock in production, FrozenClock swapped in the base TestCase or via a dedicated trait.now(), Carbon::now(), date(), time(), new \DateTime() — with the injected clock. This is the real work and it is identical whether or not you install the package.token_get_all, or spatie/php-structure-discoverer) that fails CI on new direct now() calls in domain code. Without this, the abstraction decays in weeks.Compatibility. Unchanged pending verification. If someone insists on the actual package, expect one of two outcomes at v1.0.0: either the constraints were modernized and it resolves alongside current Laravel (best case — you still carry nette/di), or they were not and you fork-and-repatriate them. Either way, budget a manual audit of \DateTime behavior on PHP 8. Budget 1–3 days including legal review, versus roughly half a day to write the equivalent from scratch.
Sequencing. (a) Legal/license read at the v1.0.0 tag — do this first, it can terminate the option cheaply. (b) Diff v1.0.0 against the prior tag and read the tagged composer.json — 30 minutes, and it retires most of the open questions. (c) Two-hour source/doc read to confirm the API surface and test-clock semantics. (d) Spike: hand-rolled clock + one module migrated + tests green. (e) Call-site sweep by module, one PR per bounded context. (f) CI guard rule. (g) Retire any interim shim. Steps (a)–(d) fit inside a single sprint-week; the sweep is the only multi-sprint item and is entirely agnostic to the package choice.
Maintenance. Full ownership still transfers to you on day one, and that has not changed — but the "nothing upstream since 2018" framing must be retired. The accurate statement is: one release after a multi-year gap, single maintainer, no observable triage history. If you vendor it, every future PHP upgrade is your problem; the code is small enough that this is manageable, but it is strictly worse than owning a 40-line interface you wrote and understand.
Support. No vendor, no SLA, no community forum. The v1.0.0 documentation improves the reading experience and is a real, if minor, onboarding asset; it does not create an escalation path. Internal engineers remain the only route, and a maintainer who surfaces once every several years is not a support channel. The ramp-up cost — an hour for any PHP developer — stays low and is not where the risk lives.
Scaling. Not a concern in either direction and unchanged by the release. The provider is a stateless wrapper around DateTimeImmutable; per-call cost is negligible and it introduces no shared state, no locks, no allocation pressure. The scaling-adjacent consideration is correctness under long-lived processes rather than throughput.
Failure modes to design against.
now() will silently corrupt timestamps, expiry logic, and audit trails. Fail loudly: assert clock class at boot.handle().hrtime(); conflating the two produces negative elapsed times under NTP correction.now() and the invariant dies quietly.Ramp-up. Under a day for a mid-level PHP developer to learn the pattern and the two adapters; the new documentation may shave that further. The cost is not comprehension; it is the mechanical sweep of existing call sites and the discipline to keep them swept. That cost is identical for the package and for a homegrown equivalent — which remains the core argument for not taking on an ambiguously licensed Nette dependency to obtain a pattern the framework already ships.
How can I help you explore Laravel packages today?