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

Datetime Provider Bundle Laravel Package

kdyby/datetime-provider-bundle

A Symfony bundle that integrates kdyby/datetime-provider, giving you DI-managed date/time services so you can inject and control the current time instead of calling new DateTime directly. This makes time-dependent code testable and lets you freeze or mock "now" in your Symfony applications...

View on GitHub
Deep Wiki
Context7

Getting Started

Install and register (2 minutes)

composer require kdyby/datetime-provider-bundle:^1.0

v1.0.2 widens the Symfony constraint to include Symfony 5, so this is now the version to pin if you are on 4.4 or 5.x. Do not assume the constraint stops there — check composer why-not kdyby/datetime-provider-bundle before you plan on Symfony 6/7.

The bundle is tiny: it registers the Kdyby\DateTimeProvider\Provider\Provider service (a thin clock abstraction with now() / today() returning DateTimeImmutable) and aliases it so it can be autowired. On Symfony 4.2+ with Flex, add it to config/bundles.php (older skeletons: AppKernel::registerBundles()):

Kdyby\DateTimeProviderBundle\KdybyDateTimeProviderBundle::class => ['all' => true],

On Laravel there is no bundle. This is a Symfony bundle, not a Laravel package — there is no service provider, no auto-discovery, no facade. If you are pulling it into a Laravel app you are using only the two library classes (Provider, CurrentProvider); bind the interface yourself and skip the bundle entirely:

// app/Providers/AppServiceProvider.php
$this->app->singleton(\Kdyby\DateTimeProvider\Provider\Provider::class, \Kdyby\DateTimeProvider\Provider\CurrentProvider::class);

Where to look first

  1. bin/console debug:container Kdyby\\DateTimeProvider — confirm the service id and the alias the bundle actually wires. The bundle is sparsely documented, so the container is the source of truth.
  2. Read the two classes you will actually use: Kdyby\DateTimeProvider\Provider\Provider (interface) and Kdyby\DateTimeProvider\Provider\CurrentProvider (the default, returns real wall-clock time).
  3. Check the repo's LICENSE file — the package reports NOASSERTION, so confirm terms before adopting it in a commercial codebase.

First use case

Stop calling new \DateTime() / date() inside services. Inject the provider instead:

final class InvoiceDueDateCalculator
{
    public function __construct(private \Kdyby\DateTimeProvider\Provider\Provider $clock) {}

    public function dueDate(): \DateTimeImmutable
    {
        return $this->clock->now()->modify('+14 days');
    }
}

That single substitution is the entire value proposition: time becomes an injected dependency you can freeze in tests.

Implementation Patterns

Type-hint the interface, never the concrete class. Autowiring resolves the alias to CurrentProvider in prod/dev, and you can swap the implementation per environment without touching consumers. In Laravel the equivalent is binding the interface in a service provider and swapping the binding in a test case or a TestingServiceProvider.

Overriding the clock in the test container. On Symfony the cleanest pattern is a test-only service override in config/services_test.yaml:

services:
    Kdyby\DateTimeProvider\Provider\Provider:
        class: Kdyby\DateTimeProvider\Provider\FixedProvider
        arguments: ['@=new \\DateTimeImmutable("2024-06-01 09:00:00")']

On Laravel, do the same thing with $this->app->instance(Provider::class, new FixedProvider(new DateTimeImmutable('2024-06-01 09:00:00'))) in setUp().

For per-test control, use a mutable/fixed provider registered as a public test service and set the instant in setUp(). Note FixedProvider is fixed by design — if you need to advance time mid-test, wrap it or use a small custom Provider implementation in tests/Support/.

Refactor incrementally. Grep for the hot spots first: new \DateTime(, new \DateTimeImmutable(, date(, time(), Carbon::now(). Convert them service by service, starting with anything whose output feeds an assertion (reporting, expiry, aging, proration). Leave DTO hydration, fixtures, and DB column defaults alone — those are data mapping, not business time.

Where it pays off most

  • Domain services computing deadlines, grace periods, aging buckets.
  • Symfony Commands / Laravel console commands and scheduled jobs that decide "what is due now".
  • Anything under test that currently asserts against (new \DateTime())->format('Y-m-d') and therefore flakes at midnight or in CI timezones.

Integrating with existing timezone assumptions. CurrentProvider returns system-default-tz immutables. If your app is strict about UTC, wrap the provider in a decorator that normalizes to UTC before returning, and inject the decorator as the Provider alias — one place to enforce the rule instead of scattering setTimezone() calls.

Don't pass the provider around. Inject it at the boundary of the code that needs "now" and pass the resulting DateTimeImmutable inward. Entities and value objects should receive a concrete timestamp, not the clock.

Coexistence with Symfony Clock. The new release does not add symfony/clock integration — it is still a raw DateTimeImmutable abstraction. If the project is on Symfony 6.2+, Symfony\Component\Clock\ClockInterface / ClockMock is the native equivalent and is what new code should use. The pragmatic migration is a small adapter that implements Kdyby\DateTimeProvider\Provider\Provider and delegates to ClockInterface, so this bundle's consumers keep working while the rest of the app moves to Clock. On Laravel 10+, Illuminate\Support\Carbon::setTestNow() covers most of the same ground without a dependency.

Gotchas and Tips

v1.0.2 is a constraint bump, not a revival. The only change is "Allow Symfony 5" — no code changes, no deprecations, no features. Nothing you read above about behaviour changes. It does mean the package is not dead dead (someone is still merging), but expect no Symfony 6/7 support and no symfony/clock bridge. Verify it installs against your version before committing; if it doesn't, the classes are trivial to vendor into src/ and wire yourself. Also note Symfony 5 itself is EOL, so "supports Symfony 5" is not a durable answer.

License is NOASSERTION. Composer cannot identify the license from the manifest. Open the LICENSE file manually — treat this as a blocker for adoption until resolved. The new release did not change this.

Autowiring may silently fail. Because the bundle is old, the alias might be registered without public: true or under a non-obvious id. debug:autowiring Provider will show whether the interface is wired. If it isn't, add the alias yourself in services.yaml — do not let it bind to a wrong default. In Laravel there is no alias at all until you create the binding.

DateTime vs DateTimeImmutable. Older code paths in your app may expect mutable DateTime. The provider returns immutables. Passing them where a mutable is type-hinted is a fatal type error, not a coercion — check signatures of any legacy method you feed with ->now().

Mocks leak. A CurrentProvider that gets new'd inside a class instead of injected defeats the whole point. Watch for new CurrentProvider() appearing in application code; that's always a wiring mistake.

Freezing time is not the same as freezing the timezone. Tests that pass locally but fail in CI usually differ in date.timezone, not in the instant. Pin date.timezone=UTC in phpunit.xml regardless of this bundle.

Debugging "wrong" times. On Symfony, confirm which implementation is actually injected with bin/console debug:container --show-arguments <your.service.id>. On Laravel, app(Provider::class)::class inside tinker is the fastest check. Half of all "the clock is wrong" reports are a FixedProvider left in a non-test config file or a leftover Carbon::setTestNow().

Extension point. The bundle's DI extension is minimal and v1.0.2 added no config keys. The sanctioned override remains a compiler-pass-free service replacement: redefine the alias in your app's services.yaml (or the container binding in Laravel). Keep that override in one file and comment why — future readers will otherwise assume it is bundle-provided behaviour.

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.
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
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource