Product Decisions This Supports
- Timezone correctness as a product feature, not a bug fix. v3.1.0 makes the write path explicit: user-entered date strings are interpreted in the authenticated user's timezone and persisted in the application timezone. That lets us promise "the date you typed is the date we store, wherever you are" — a prerequisite for any scheduling, billing-period, or compliance-deadline feature that spans regions.
- Roadmap flexibility on legacy surfaces. Automatic recognition of legacy date fields alongside current
date/datetime casts means we can migrate an existing schema incrementally instead of doing a big-bang column rename. That removes a large chunk of work from any "modernise the data model" epic.
- Lower upgrade tax. Laravel 5.1 → 13 and PHP 5.5.9+ support means the same package spans our oldest service and our newest one. Concretely: one dependency decision, one code review, one security posture — instead of a fork per Laravel major.
- Fewer silent data bugs. Passing nullable dates through unchanged and cloning returned Carbon values both eliminate a class of "the value changed just because something read it" defects. That is the kind of bug that shows up as off-by-one-day invoice dates and is expensive to trace post-hoc.
- Build vs buy: the alternative is hand-rolling a cast/trait plus timezone handling in every model. With ~5 behaviours covered here (nullability, legacy fields, cast detection, user-TZ interpretation, immutability on read), buying is clearly cheaper if our auth model matches the package's assumption.
When to Consider This Package
Adopt when:
- Users are in more than one timezone and they enter dates through authenticated web/mobile flows (the package's core assumption holds).
- The domain has Eloquent date/datetime attributes whose stored value has business meaning — billing periods, SLAs, deadlines, appointments — not just audit timestamps.
- We are mid-migration from legacy date columns and cannot rename them all at once.
- The estate is version-heterogeneous (Laravel 5.x through 13) or still carries PHP 5.5.9-era constraints, and a single dependency must serve both ends.
- We have been bitten by Carbon mutation on read, or by null dates being coerced into
0000-00-00 / epoch values.
Look elsewhere / push back when:
- No authenticated user at write time. Console commands, queued jobs, imports, webhooks, and service-to-service writes have no session user, so "interpret in the user's timezone" is undefined. Every such path needs an explicit timezone argument or an
auth()->user() fallback we control. This is the single biggest integration risk and should be validated in a spike before commit.
- Behavioural change on existing data. If users previously entered strings that were interpreted in app timezone, this release silently shifts stored values for those users. We need a decision: accept the drift, backfill, or gate behind a config flag with a cutover date. Treat v3.1.0 as a migration, not a patch.
- Greenfield on PHP 8.2+ / Laravel 11+ only. PHP 5.5.9 support is a compatibility promise that constrains the codebase (no typed properties, no enums, no modern Carbon APIs). We inherit an EOL floor we would not otherwise accept. If we have no legacy constraint, a small in-house cast is likely cleaner and fully typed.
- We need immutability guaranteed everywhere. Cloning on read fixes the read path; the write path and any direct attribute access still need review.
- No maintained test matrix or security advisories for the older Laravel/PHP combinations — vendor support for EOL runtimes is a risk we must accept explicitly, not accidentally.
Open questions to close before adoption: Where does the user timezone come from (column, session, header)? What is the fallback for anonymous requests? Is the package config-driven or convention-driven? Does it handle DST-ambiguous local times (the 2:00–3:00 gaps and repeats)?
How to Pitch It (Stakeholders)
For executives: We are standardising how dates from users around the world get stored, so a deadline entered in Berlin means the same instant as one entered in São Paulo. This release fixes three defect classes — null dates being corrupted, read operations mutating values, and timezone ambiguity on write — and it does so without forcing an upgrade of our older Laravel services or a schema rewrite. Low integration cost, one dependency, applies across the whole estate.
For engineering: v3.1.0 is a correctness release with one behavioural change to plan for. Nullable dates now pass through untouched; both legacy date fields and current date/datetime casts are recognised; inbound strings are resolved in the authenticated user's timezone and stored in app timezone; returned Carbon instances are cloned so reads no longer mutate model state. Support spans Laravel 5.1–13 on PHP 5.5.9+. Two things we must handle: (1) the write-path timezone change is a data migration — existing rows written under app-timezone interpretation may need backfill or a gated cutover; (2) the "authenticated user" assumption does not hold in jobs, commands, imports, or webhooks, so those call sites need an explicit timezone. Recommend a short spike to confirm DST edge-case behaviour and the anonymous-user fallback before we adopt across services.