Store all dates in UTC database timestamps and use Eloquent date casting and Carbon accessors for display formatting.
Parsing date strings repeatedly inside Blade views with manual Carbon::parse($order->ordered_at)->format('M d, Y') calls is slow, repetitive, and fails if the column value is null.
Eloquent date casting automatically converts database timestamp strings into immutable Carbon instances upon retrieval.
Defining Date Casts on Models
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Subscription extends Model
{
protected function casts(): array
{
return [
'starts_at' => 'datetime',
'ends_at' => 'datetime',
'trial_ends_at' => 'immutable_datetime',
];
}
}
Accessing Fluent Carbon Methods
Once cast, properties automatically return Carbon instances with full date math and comparison capabilities:
$subscription = Subscription::find(1);
// Date comparison
if ($subscription->ends_at->isPast()) {
$subscription->markAsExpired();
}
// Relative human diffs
echo $subscription->ends_at->diffForHumans(); // "in 3 days"
In Blade Templates
<p class="text-sm">
Subscription active until {{ $subscription->ends_at->format('M d, Y') }}
</p>
Summary
- Store timestamps in standard SQL
TIMESTAMP/DATETIMEformat in UTC. datetimeandimmutable_datetimecasts ensure attributes hydrate as Carbon instances.- Simplifies timezone conversions, relative formatting, and chronological comparisons.
Related Tips
View all tips →Refresh and Pessimistically Lock Models with refreshForUpdate() in Laravel 13.27
Laravel 13.27 adds refreshForUpdate(), reloading an existing model instance in-place with fresh database attributes while acquiring an exclusive FOR UPDATE row lock.
Scope Pivot Table Queries with Closures in wherePivot() in Laravel 13.26
Laravel 13.26 allows wherePivot() and orWherePivot() to accept closures, enabling direct reuse of local scopes defined on custom Pivot models.