lightsuner/carbon-bundle
LightSuner Carbon Bundle integrates Carbon, the popular PHP DateTime extension, into Symfony applications. It provides Carbon services, Twig filters, Doctrine types, and form helpers, making date and time handling cleaner, more expressive, and consistent across your Symfony projects.
Know what you're actually installing. CarbonBundle is a Symfony 2 bundle whose job is to register Carbon as a container service so you can inject a configured date object instead of scattering new \Carbon\Carbon() through your code. If you are working in a Laravel application, you almost certainly should not install it: Laravel already ships nesbot/carbon and aliases Illuminate\Support\Carbon, and this bundle's Symfony 2 kernel wiring has no meaning in a Laravel service container.
If you inherited a Symfony 2 app that uses it (or you're porting one to Laravel), the minimal path is:
composer require lightsuner/carbon-bundle — check the constraint resolution first, because the package's last release is from 2018-11-30 and it will pin or tolerate only older nesbot/carbon lines.new LightSuner\CarbonBundle\CarbonBundle() in app/AppKernel.php.DependencyInjection/ and Resources/config/services.yml in vendor/lightsuner/carbon-bundle/ before writing any code — the service id, its visibility (public vs private), and whether locale/timezone are constructor arguments or parameters are the only three facts you need, and the README is likely to be thinner than the source.php app/console debug:container carbon (or debug:container --tag=…) and debug:container --parameters | grep -i carbon.First use case worth the wiring: a single injected date factory used by domain services, rather than Carbon::now() calls embedded in entities and controllers. That indirection is what makes tests freezable and is the one idea from this bundle you should carry into Laravel.
The Laravel-native equivalent of step 3–4 is a one-liner in a service provider, no package required:
// AppServiceProvider::boot()
Carbon::setLocale(config('app.locale'));
Carbon::setFallbackLocale('en');
date_default_timezone_set(config('app.timezone'));
Inject a clock, not a Carbon instance. The bundle's pattern (a container-managed date service) is right; copying the shape is more useful than copying the code. Wrap it:
final class Clock
{
public function now(): CarbonImmutable
{
return CarbonImmutable::now(config('app.timezone'));
}
}
Bind it as a singleton in AppServiceProvider::register() and you have the same "configured date service" the bundle was selling, plus a seam for Carbon::setTestNow().
Keep configuration at boot, never per call. Locale, timezone, and first-day-of-week belong in one place — the bundle's DI extension in Symfony, AppServiceProvider::boot() in Laravel. If you find ->locale('fr') sprinkled through views, that's the smell this bundle exists to prevent.
Prefer CarbonImmutable at boundaries. Jobs, API resources, DTOs, and model casts should carry immutable dates; mutable Carbon only where you are deliberately doing arithmetic in place. This matters more than which wrapper package you use.
Freeze time in tests, uniformly. Carbon::setTestNow('2024-03-01 12:00:00') in setUp(), Carbon::setTestNow() in tearDown(). Every assertion about "3 days ago" depends on this being consistent across the suite, and the container-injected clock makes it work without touching production code.
Symfony-side integration tips if you must stay there: keep the bundle's service private and inject it (or an interface you own); add a compiler pass only if you need to override locale/timezone from a parameter; and if you're bridging toward Laravel later, write an adapter interface now so the Symfony service and the Laravel binding can both satisfy it.
Laravel-side equivalents of the bundle's extension points: Date::use(CarbonImmutable::class), Carbon::macro() for project-wide helpers, and a DateFactory binding in the container. These give you the "one configured entry point" without a Symfony-only dependency.
nesbot/carbon tightly (^2.x or ^3.x depending on version). This bundle predates Carbon 2's namespace/behavior changes and certainly predates Carbon 3. Run composer why nesbot/carbon before and after; if the bundle forces a downgrade of the framework's Carbon, stop.#[\ReturnTypeWillChange]-era signatures, Stringable, and dynamic properties. Don't assume it loads under PHP 8.x just because Composer resolved.Carbon::setTestNow() and Carbon::setLocale() are static. A test that freezes time without unfreezing will silently corrupt later tests, and the failure will look like a timezone bug in your code. Always pair set/unset in tearDown().Carbon instance into a service that does ->addDay() mutates the caller's object. Type-hint CarbonImmutable or clone at the boundary; PHP won't warn you.diffForHumans() silently falls back to English when intl is missing or locale isn't set. If output is English in a non-English app, check the locale was set at boot, not that the bundle is broken.app.timezone, and constructing with Carbon::now() (server default TZ) are three different things. The bundle's configured service — or your own Clock — should be the only place now() is called, otherwise the "configured" timezone is cosmetic.debug:container <service> to see whether the service exists and is public; if it's private, debug:container plus a #[\Symfony\...\Required]-style injection or a public alias is your workaround. In Laravel, app(Clock::class) and dd(Carbon::now()->tz) answer the same questions faster.mergeConfigFrom() plus a singleton binding — same idea, no bundle.How can I help you explore Laravel packages today?