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+.
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).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."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
composer require brick/date-time), PSR-4 autoloaded, no bootstrapping. Optional Doctrine persistence via brick/date-time-doctrine.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.fromNativeDateTime(), toNativeDateTimeImmutable(), fromNativeDateInterval(), toNativeDatePeriod()), which materially lowers integration cost and enables a strangler-style rollout.Technical risk
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.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.Key questions
JsonSerializable/Stringable consistently, and what is the serialized wire format across 0.x cycles (API contract stability)?TimeZoneRegion — does it consume PHP's bundled tzdata, and how are DST gaps/overlaps resolved?0.x.0 diffs in practice?brick/date-time-doctrine cover the DB platforms we run (MySQL/Postgres timestamptz), and how are partial types (LocalDate) persisted?Stack fit
brick/date-time:0.4.* (or the current cycle) explicitly in composer.json; do not allow ^0.x floats.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
LocalDateRange/Interval/YearMonth). Leave existing Carbon code untouched.fromNativeDateTimeImmutable()/toNativeDateTimeImmutable() as the universal seam so persistence and framework code never see brick types directly.Compatibility
Sequencing
FixedClock. Validate serialization and DST behavior.DefaultClock).DefaultClock and Carbon::setTestNow()").0.x.0 release.Maintenance
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.Support
Scaling
LocalDate over repeated string parsing.TimeZoneRegion lookups depend on tzdata; cache aggressively if converting millions of instants per job.--daemon, and Swoole-style runtimes retain static DefaultClock state. Reset per request/job via middleware and job middleware.Failure modes
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.LocalDateTime has no zone; mapping to ZonedDateTime at a non-existent local time must be an explicit, tested policy.DateTimeParseException on inputs Carbon would have accepted — validation must run before construction to avoid 500s.0.x.0 bump silently changing method signatures will surface at deploy if the lockfile is loosened.Ramp-up
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.Brick\DateTime directly.DateTime type makes easy to write.How can I help you explore Laravel packages today?