Weave Code
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

Immutable, ISO-8601–focused date/time API for PHP 8.2+ built on top of native DateTime, adding missing types like LocalDate, LocalTime, YearMonth, and MonthDay. Inspired by Java’s JSR-310, well-tested, production-ready, Composer installable.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require brick/date-time
    

    Requires PHP 8.2+.

  2. First Use Case: Replace native DateTime with Brick\DateTime for immutable operations:

    use Brick\DateTime\LocalDate;
    use Brick\DateTime\TimeZone;
    
    $today = LocalDate::now(TimeZone::utc());
    echo $today; // Outputs: YYYY-MM-DD (e.g., 2023-10-05)
    
  3. Key Classes to Explore:

    • LocalDate (immutable dates like 2023-10-05).
    • ZonedDateTime (timezone-aware, like PHP’s DateTime but immutable).
    • Duration/Period (time intervals, e.g., PT2H30M).
    • Clock utilities (for testing, e.g., FixedClock).
  4. Where to Look First:

    • API Docs (autogenerated via PHPDoc).
    • LocalDate::now() and ZonedDateTime::now() for common use cases.
    • DefaultClock for test time manipulation (see Testing).

Implementation Patterns

Core Workflows

1. Date/Time Creation and Manipulation

  • Immutable Operations:
    $date = LocalDate::of(2023, 10, 5);
    $nextMonth = $date->withMonth(11); // Returns new instance
    
  • Timezone Handling:
    $zoned = ZonedDateTime::of(2023, 10, 5, 12, 0, 0, TimeZone::of('Europe/London'));
    $utc = $zoned->withTimeZone(TimeZone::utc());
    
  • Parsing:
    $date = LocalDate::parse('2023-10-05');
    $zoned = ZonedDateTime::parse('2023-10-05T12:00:00+01:00');
    

2. Arithmetic and Comparisons

  • Add/Subtract:
    $duration = Duration::ofHours(2);
    $futureDate = $date->plus($duration);
    
  • Intervals:
    $interval = Interval::between($date1, $date2);
    echo $interval->toDuration(); // PT... (ISO 8601)
    
  • Comparisons:
    if ($date1->isBefore($date2)) { ... }
    

3. Testing with Clocks

  • Freeze Time:
    use Brick\DateTime\DefaultClock;
    
    DefaultClock::freeze(Instant::of(1696476800)); // 2023-10-05T00:00:00Z
    $date = LocalDate::now(TimeZone::utc()); // Always returns 2023-10-05
    
  • Time Travel:
    DefaultClock::travelTo(Instant::of(1696563200)); // 2023-10-06T00:00:00Z
    DefaultClock::travelBy(Duration::ofDays(1)); // +1 day
    
  • Reset After Tests:
    DefaultClock::reset(); // Back to system time
    

4. Integration with Laravel

  • Carbon Replacement: Replace Carbon\Carbon with ZonedDateTime for immutable operations:
    $now = ZonedDateTime::now(); // Instead of Carbon::now()
    
  • Query Builder: Use LocalDate for database queries:
    $results = Model::whereDate('created_at', $date->toDateTimeString())->get();
    
  • Form Requests: Parse user input with LocalDate::parse():
    $date = LocalDate::parse($request->input('date'));
    

5. Common Patterns

  • Date Ranges:
    $range = LocalDateRange::between($start, $end);
    if ($range->contains($date)) { ... }
    
  • Business Logic:
    $nextBusinessDay = $date->nextOrSameDayOfWeek(DayOfWeek::MONDAY);
    
  • Time Zones:
    $tz = TimeZone::of('America/New_York');
    $localTime = $zoned->toLocalTime($tz);
    

Laravel-Specific Tips

  1. Service Providers: Bind DefaultClock to a singleton for global test control:

    $this->app->singleton(DefaultClock::class, function () {
        return new FixedClock(Instant::now()); // Or system clock
    });
    
  2. Model Casting: Use Brick\DateTime\Casts\LocalDate in Eloquent:

    use Brick\DateTime\Casts\LocalDate;
    
    class Event extends Model {
        protected $casts = [
            'event_date' => LocalDate::class,
        ];
    }
    
  3. API Responses: Serialize dates to ISO strings:

    return response()->json([
        'event_date' => $event->event_date->toIsoString(),
    ]);
    
  4. Validation: Use LocalDate::parse() in Form Requests:

    $this->validate($request, [
        'date' => 'required|date_format:Y-m-d',
    ]);
    $date = LocalDate::parse($request->date);
    

Gotchas and Tips

Pitfalls

  1. Immutability:

    • All operations return new instances; avoid chaining without assignment:
      // ❌ Loses reference
      $date->plus(Duration::ofDays(1))->minus(Duration::ofHours(1));
      // ✅ Correct
      $newDate = $date->plus(Duration::ofDays(1))->minus(Duration::ofHours(1));
      
  2. Time Zone Handling:

    • ZonedDateTime is not equivalent to PHP’s DateTime. Use TimeZone::of() explicitly:
      // ❌ Ambiguous
      $zoned = new ZonedDateTime('2023-10-05T12:00:00');
      // ✅ Explicit
      $zoned = ZonedDateTime::of(2023, 10, 5, 12, 0, 0, TimeZone::utc());
      
  3. Clock Leaks:

    • Forgetting to reset() DefaultClock in tests causes flaky tests:
      // ❌ Test pollution
      DefaultClock::freeze(...);
      // ... other tests run with frozen time
      // ✅ Reset in tearDown()
      public function tearDown(): void {
          DefaultClock::reset();
      }
      
  4. Deprecated Methods:

    • Avoid DayOfWeek::monday(); use DayOfWeek::MONDAY (enum):
      // ❌ Deprecated
      $day = DayOfWeek::monday();
      // ✅ Modern
      $day = DayOfWeek::MONDAY;
      
  5. Duration vs. Period:

    • Duration = time-based (e.g., PT2H30M).
    • Period = calendar-based (e.g., P2Y3M4D).
    • Mixing them causes unexpected results:
      $date->plus(Duration::ofDays(32)); // Correct (32 days)
      $date->plus(Period::ofDays(32));   // May wrap months (e.g., Jan 31 + 32 days = Mar 4)
      
  6. Parser Strictness:

    • parse() throws DateTimeParseException on invalid input:
      try {
          $date = LocalDate::parse('invalid-date');
      } catch (DateTimeParseException $e) {
          // Handle error
      }
      
  7. PHP 8.2+ Features:

    • Uses named arguments and enums. Older PHP versions will fail.

Debugging Tips

  1. Clock Issues:

    • Check if DefaultClock is overridden:
      echo DefaultClock::get()->getClass(); // Should be SystemClock in production
      
  2. Time Zone Confusion:

    • Use toTimeZone() to debug:
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky