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

Period Laravel Package

league/period

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require league/period
    

    Add to composer.json if using Laravel’s require-dev or require explicitly.

  2. First Use Case: Creating a Period

    use League\Period\Period;
    
    // Create a period from two DateTimeImmutable objects
    $period = Period::createFromDateTimeImmutable(
        new DateTimeImmutable('2023-01-01'),
        new DateTimeImmutable('2023-12-31')
    );
    
  3. Key Classes to Know

    • Period: Represents a time range (immutable).
    • Period\Bounds: Defines the start/end boundaries (e.g., Bounds::inclusive()).
    • Period\Interval: Represents a fixed duration (e.g., Interval::day(1)).
  4. Where to Look First

    • Official Docs (API reference + examples).
    • src/Period.php for core logic (if extending).
    • tests/ for edge-case patterns (e.g., invalid ranges).

Implementation Patterns

Core Workflows

  1. Period Creation

    // From strings
    $period = Period::createFromString('2023-01-01', '2023-12-31');
    
    // From DateTime objects (Laravel-friendly)
    $start = now()->startOfDay();
    $end = now()->endOfDay();
    $period = Period::createFromDateTime($start, $end);
    
    // With bounds (e.g., half-open intervals)
    $period = Period::create(
        new DateTimeImmutable('2023-01-01'),
        new DateTimeImmutable('2023-12-31'),
        Bounds::inclusive(),
        Bounds::exclusive()
    );
    
  2. Common Operations

    // Check if a DateTime is within the period
    $isInPeriod = $period->contains($dateTime);
    
    // Get the duration (as Interval)
    $duration = $period->duration();
    
    // Iterate over days/weeks (useful for Laravel scheduling)
    foreach ($period->days() as $day) {
        // Process each day
    }
    
    // Convert to Carbon (Laravel interop)
    $start = $period->getStart()->toCarbon();
    $end = $period->getEnd()->toCarbon();
    
  3. Laravel-Specific Patterns

    • Carbon Integration:
      use League\Period\Period;
      use Carbon\Carbon;
      
      $period = Period::createFromDateTimeImmutable(
          Carbon::parse('2023-01-01'),
          Carbon::parse('2023-12-31')
      );
      
    • Query Scoping:
      $query->whereBetween('created_at', [
          $period->getStart()->format('Y-m-d'),
          $period->getEnd()->format('Y-m-d')
      ]);
      
    • Task Scheduling:
      $schedule->command('daily-report')->dailyAt('09:00')->between(
          $period->getStart()->format('Y-m-d'),
          $period->getEnd()->format('Y-m-d')
      );
      
  4. Advanced: Custom Periods

    // Create a recurring period (e.g., every Monday)
    $mondays = Period::createFromDateTimeImmutable(
        new DateTimeImmutable('2023-01-02'), // First Monday
        new DateTimeImmutable('2023-12-25')
    )->filter(function (DateTimeImmutable $date) {
        return $date->format('N') === '1'; // Monday
    });
    

Gotchas and Tips

Pitfalls

  1. Immutable Objects

    • Periods are immutable. Avoid modifying start/end directly; create new instances:
      $newPeriod = $period->withStart($newStartDate);
      
  2. Bounds Confusion

    • Default bounds are inclusive() for both start/end. Explicitly set bounds if using half-open intervals:
      $period = Period::create($start, $end, Bounds::inclusive(), Bounds::exclusive());
      
  3. Timezone Sensitivity

    • Periods use the UTC timezone by default. Convert to local time explicitly:
      $period->getStart()->setTimezone(new DateTimeZone('America/New_York'));
      
  4. Edge Cases in contains()

    • contains() respects bounds. For example, an exclusive end will exclude the end date:
      $period = Period::create($start, $end, Bounds::inclusive(), Bounds::exclusive());
      $period->contains($end->modify('+1 second')); // false
      
  5. Performance with Large Periods

    • Iterating over large periods (e.g., years) can be memory-intensive. Use generators or chunking:
      foreach ($period->days() as $day) {
          // Process in batches
      }
      

Debugging Tips

  1. Visualize Periods

    echo $period->getStart()->format('Y-m-d H:i:s') . ' to ' .
         $period->getEnd()->format('Y-m-d H:i:s');
    
  2. Check Bounds

    $period->getStartBounds()->isInclusive(); // bool
    $period->getEndBounds()->isExclusive();   // bool
    
  3. Validate Inputs

    • Ensure startend; otherwise, throw InvalidArgumentException:
      if ($start > $end) {
          throw new \InvalidArgumentException('Start must be before end.');
      }
      

Extension Points

  1. Custom Iterators Override Period::days()/weeks() for business-specific logic:

    $period->filter(function (DateTimeImmutable $date) {
        return $date->format('w') === '5'; // Only Fridays
    });
    
  2. Laravel Service Provider Bind Period to the container for dependency injection:

    $this->app->bind(Period::class, function () {
        return Period::createFromDateTimeImmutable(
            now()->startOfDay(),
            now()->endOfDay()
        );
    });
    
  3. Testing Use PeriodFactory for test doubles:

    $mockPeriod = Period::createFromDateTimeImmutable(
        new DateTimeImmutable('2023-01-01'),
        new DateTimeImmutable('2023-01-02')
    );
    $this->assertTrue($mockPeriod->contains(new DateTimeImmutable('2023-01-01')));
    
  4. Serialization Periods are not JSON-serializable by default. Use a custom encoder:

    $serialized = [
        'start' => $period->getStart()->format('Y-m-d H:i:s'),
        'end' => $period->getEnd()->format('Y-m-d H:i:s'),
        'startBounds' => $period->getStartBounds()->value,
        'endBounds' => $period->getEndBounds()->value,
    ];
    
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.
make-dev/orca
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle
dmstr/api-platform-utils-bundle
dmstr/api-configuration-bundle
chrisdev/ux-components
baks-dev/finances
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle