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

Date Time Laravel Package

brick/date-time

A powerful set of immutable PHP date-time classes built on native PHP and following ISO 8601, inspired by Java's JSR 310. Adds missing concepts such as LocalDate, LocalTime, YearMonth, and MonthDay. Requires PHP 8.2+.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • brick/date-time is a framework-agnostic, pure-PHP value-object library — no service provider, no facades, no Laravel coupling. It sits alongside Laravel's default stack (Carbon 2/3 wrapping DateTimeImmutable) rather than replacing it, which is both its strength (clean domain model, no framework lock-in) and its main architectural tension (two date-time models in one codebase).
  • Fit is strongest where the domain genuinely needs concepts Carbon models poorly: LocalDate, YearMonth, MonthDay, Interval/LocalDateRange, nanosecond-precision Instant, and strict ISO-8601 parsing. Weakest where the team only needs "add a week to a timestamp."
  • Immutability-by-default and final classes map cleanly onto DDD-style domain layers, DTOs, and event payloads. The Clock abstraction (SystemClock, FixedClock, OffsetClock, ScaleClock) is a genuine testing asset that Laravel's Carbon::setTestNow() partially duplicates — the two mechanisms must not be mixed.

Integration feasibility

  • Trivial to install (composer require brick/date-time), PSR-4 autoloaded, no bootstrapping. Optional Doctrine persistence via brick/date-time-doctrine.
  • Non-trivial work sits at the framework seams: Eloquent casts (CastsAttributes), validation rules, JSON/API serialization shape, queue payloads, Blade formatting, and Nova/Filament column formatting all assume Carbon or native DateTimeInterface. Each needs a thin adapter.
  • Bidirectional native interop exists (fromNativeDateTime(), toNativeDateTimeImmutable(), fromNativeDateInterval(), toNativeDatePeriod()), which materially lowers integration cost and enables a strangler-style rollout.

Technical risk

  • Pre-1.0 versioning contract: 0.x.y where any breaking change forces a new 0.x cycle. Safe only if pinned (0.4.*); every cycle bump is a planned migration, not a patch.
  • Global mutable state: DefaultClock::set()/freeze()/travelTo() affect all classes statically. Under Octane, Horizon workers, or long-lived processes this leaks across requests/jobs unless explicitly reset — the README itself flags reset() in tearDown(), which is a hint at the failure mode.
  • Ecosystem signal: 0 listed dependents and a single-maintainer project (albeit with CI, PHPStan, ECS, Rector, codecov). Bus factor and long-term maintenance are the real risks, not code quality.
  • Dual-model drift: Carbon stays in the framework layer regardless; inconsistent conversion points create subtle timezone/precision bugs at boundaries.
  • PHP 8.2 floor is fine for Laravel 11/12 but blocks older LTS branches.

Key questions

  1. Does it implement JsonSerializable/Stringable consistently, and what is the serialized wire format across 0.x cycles (API contract stability)?
  2. What is the exact behavior of TimeZoneRegion — does it consume PHP's bundled tzdata, and how are DST gaps/overlaps resolved?
  3. Under Octane/queues, is there any request-scoped reset pattern endorsed upstream, or must we build middleware?
  4. What is the maintainer's stated 1.0 timeline, and how large are historical 0.x.0 diffs in practice?
  5. Does brick/date-time-doctrine cover the DB platforms we run (MySQL/Postgres timestamptz), and how are partial types (LocalDate) persisted?
  6. What is the measured performance delta vs Carbon in our hot paths (report generation, scheduling loops)?

Integration Approach

Stack fit

  • Target Laravel 11/12 on PHP 8.2+. Pin brick/date-time:0.4.* (or the current cycle) explicitly in composer.json; do not allow ^0.x floats.
  • Treat it as a domain-layer dependency, not an application-wide replacement. Framework-facing surfaces — validation, Eloquent, Blade, notifications, HTTP resources — keep Carbon/native types and convert at the boundary.
  • Optional: a small internal package (app/Support/DateTime or a private Composer package) exposing casts, validation rules, a ClockServiceProvider, and formatting helpers. This confines the third-party API surface and makes a future swap cheap.

Migration path

  • Strangler pattern: adopt in one bounded context first (scheduling, billing periods, availability windows — anything that benefits from LocalDateRange/Interval/YearMonth). Leave existing Carbon code untouched.
  • Introduce adapters in this order: (1) custom Eloquent casts, (2) FormRequest/validation rules, (3) JSON resource serialization to ISO-8601 strings, (4) clock binding for tests.
  • Use fromNativeDateTimeImmutable()/toNativeDateTimeImmutable() as the universal seam so persistence and framework code never see brick types directly.

Compatibility

  • Native interop is good and explicitly maintained; leverage it rather than writing conversions by hand.
  • Serialization must be normalized deliberately: pick ISO-8601 strings at the API edge so Carbon-sourced and brick-sourced responses are indistinguishable to clients.
  • Doctrine only matters if the stack uses Doctrine; on pure Eloquent, the companion package is irrelevant.

Sequencing

  1. Spike: one domain object + one cast + one test using FixedClock. Validate serialization and DST behavior.
  2. Add the internal helper package (casts, rules, provider, test trait that resets DefaultClock).
  3. Ship behind a feature flag in the pilot bounded context; keep Carbon at the edges.
  4. Document conventions ("brick inside, Carbon at the boundary", "never mix DefaultClock and Carbon::setTestNow()").
  5. Expand module by module; only then evaluate Doctrine mappings and any legacy backfill.
  6. Establish a standing upgrade task per 0.x.0 release.

Operational Impact

Maintenance

  • Recurring cost is tied to the pre-1.0 cadence: each 0.x.0 may break (final classes, removed deprecated methods, return types, signature changes such as TimeZoneOffset second removal). Budget a small upgrade ticket per cycle rather than treating it as a fire-and-forget dependency.
  • Single-maintainer risk is real; mitigate with a pinned version, a committed lockfile, an internal fork/patched-copy contingency, and by keeping all usage behind the internal adapter package so replacement is a contained exercise.
  • Quality signals are positive: CI, coverage badge, PHPStan/ECS/Rector tooling, changelog and release notes maintained.

Support

  • Community-only support via GitHub issues; no SLA, no commercial backing. Internal ownership (one named engineer or guild) is required.
  • Add it to the dependency-review and security-advisory watchlist; no CVE history given, but the surface is small and pure-PHP.

Scaling

  • Immutable value objects are lightweight; expect comparable or better memory behavior than Carbon for high-volume domain objects. Watch allocation churn inside tight loops (report generators, pricing engines) and prefer LocalDate over repeated string parsing.
  • TimeZoneRegion lookups depend on tzdata; cache aggressively if converting millions of instants per job.
  • Long-running processes are the real scaling concern: Octane workers, Horizon queues with --daemon, and Swoole-style runtimes retain static DefaultClock state. Reset per request/job via middleware and job middleware.

Failure modes

  • Clock leakage: a test (or a scheduled task) freezes/travels the DefaultClock and never resets, producing wrong timestamps in production. Highest-probability, highest-impact failure. Mitigate with a test trait that resets in tearDown() and a request/job middleware reset.
  • Serialization drift: different output formats between Carbon-backed and brick-backed endpoints breaks API consumers silently.
  • Boundary ambiguity: dates crossing the adapter layer twice pick up timezone or precision changes (e.g., local time → UTC → local).
  • DST gaps/overlaps: LocalDateTime has no zone; mapping to ZonedDateTime at a non-existent local time must be an explicit, tested policy.
  • Parse strictness: DateTimeParseException on inputs Carbon would have accepted — validation must run before construction to avoid 500s.
  • Upgrade breakage: a 0.x.0 bump silently changing method signatures will surface at deploy if the lockfile is loosened.

Ramp-up

  • The API is JSR-310/Java-flavored (LocalDate, Period, Instant, ZonedDateTime) and will feel unfamiliar to Laravel developers raised on Carbon's fluent helpers. Expect 1–2 sprints for a mid-level team to be productive, plus a written conventions doc.
  • Provide 3–4 canonical recipes: "store a date", "compare in a timezone", "build a date range", "freeze time in a test". Keep the internal helper package's API small so most engineers never touch Brick\DateTime directly.
  • Interview/onboarding cost is concentrated and one-time; the payoff is a domain model that no longer conflates "date," "local time," and "instant" — the class of bug that Carbon's single DateTime type makes easy to write.
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.
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
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core