Out of the box, unless using an attribute mutator method, Laravel will set and persist a datetime attribute as-is - i.e. without first setting the timezone to the application (or any other) timezone. However, on fetching the value from the database, it also doesn't explicitly set any timezone on an instantiated datetime. The result of this is that a datetime persisted in a specific timezone, when fetched, can have the correct string value, but a completely different timezone.
This has been raised as a framework bug a number of times - e.g. - but the thinking behind it is that it should be the user who decides in which timezone datetimes should be saved (despite the fact that the application assumes to know in which timezone to instantiate a datetime from the database!).
laravel-timezones provides a trait, UsesTimeZonesTrait
, which overrides the default behaviour of the fromDateTime
and asDateTime
methods (of the HasAttributes
trait) to ensure consistent and flexible handling of datetimes with timezones.
Add UsesTimeZonesTrait
to models individually, or to a base model, and your models' datetime attributes will consistently be instantiated using the application timezone.
Add a $timezone
property - e.g. protected $timezone = 'Europe/London'
- to your model to define an alternative timezone for that model alone. N.B. This timezone will also apply to the model's created_at
and updated_at
timestamp attributes.
Add mutator and accessor attribute methods to your model and use the methods from UsesTimeZonesTrait
to define alternative timezones on individual attributes, overriding any timezone also specified in the model's $timezone
property or by the application.
public function setEuropeLondonAttribute($value): void
{
$this->attributes['europe_london'] = $this->fromDateTime($value, 'Europe/London');
}
public function getEuropeLondonAttribute($value): DateTimeInterface
{
return $this->asDateTime($value, 'Europe/London');
}