Skip to content

Date and time handling

1. Standard datetime format

  • Use ISO8601 for both frontend and backend when exchanging datetime data
  • Example: 2025-05-02T15:30:00+07:00

2. Register CarbonImmutable globally

php
<?php

declare(strict_types=1);

namespace App\Providers;

use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\ServiceProvider;

final class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Date::use(CarbonImmutable::class);
    }
}

3. Type hinting datetime parameters

  • Use CarbonInterface when you need Carbon's utility API
  • Use DateTimeInterface for simpler cases
php
<?php

declare(strict_types=1);

namespace App\Services;

use Carbon\CarbonInterface;
use DateTimeInterface;

final class TimeService
{
    public function handleViaCarbon(CarbonInterface $when): void
    {
        // …
    }

    public function logCreatedAt(DateTimeInterface $timestamp): void
    {
        // …
    }
}

4. Why use CarbonImmutable

Problem with Carbon (mutable)How CarbonImmutable helps
$dt->addDay() mutates the original $dtMethods return a new instance
Side effects are hard to debugImmutability makes behavior predictable
setTimezone() can have broad impactNo side effects
php
$expiresAt = Carbon::now();
cache(['key' => 'value'], $expiresAt->addMinutes(5)); // $expiresAt is mutated!
doSomething($expiresAt);                              // wrong time

$expiresAt = CarbonImmutable::now();
cache(['key' => 'value'], $expiresAt->addMinutes(5)); // $expiresAt stays unchanged
doSomething($expiresAt);                              // correct

5. Casting in Eloquent models

php
<?php

declare(strict_types=1);

namespace App\Models;

use Carbon\CarbonImmutable;
use Illuminate\Database\Eloquent\Model;

/**
 * @property CarbonImmutable          $created_at
 * @property CarbonImmutable          $updated_at
 * @property CarbonImmutable|null     $delivery_date
 * @property CarbonImmutable|null     $start_time
 * @property CarbonImmutable|null     $end_time
 */
final class Order extends Model
{
    /**
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'created_at'    => 'immutable_datetime',
            'updated_at'    => 'immutable_datetime',
            'delivery_date' => 'immutable_datetime',
            'start_time'    => 'immutable_datetime',
            'end_time'      => 'immutable_datetime',
        ];
    }
}

Note

  • Use the immutable_datetime cast (Laravel 10+)
  • Add PHPDoc so IDEs and PHPStan can check types accurately