Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jarcas's avatar
Level 1

Automatically convert datetime, timestamp, etc. to user's timezone while keeping UTC in DB? Best practices for Laravel 11?

I need to store datetimes, timestamp, etc. in UTC in the database for obvious reasons, however each user has a timezone setting they can change and I need to respect that setting.

What's the "Best way" / "Laravel way" to do this? Right now I'm using accessors like the below:

    public function getCreatedAtAttribute(){
        if (auth()->check()) {
            $timezone = (isset(auth()->user()->timezone)) ? auth()->user()->timezone : "UTC";
            return Carbon::parse($this->attributes['created_at'])->setTimezone($timezone);
        } else {
            return Carbon::parse($this->attributes['created_at'])->setTimezone("UTC");
        }
    }

However I wrote this code in Laravel 9, and it's a bit tedious to have to do for all 46 models that I have, each with the usual created_at, updated_at, and deleted_at columns - but some with custom columns that are DateTime.

Is there a better way to do this, maybe some way that Laravel 10 or 11 introduced? I could use a function to do it when needed, but I honestly can't think of a situation where, in a view or controller, I'd ever need to know the UTC date time value while accessing it. As I implied, this is something that needs to work in both a controller and view, by default, and ideally have some sort of override if I need the UTC time/date (Which I guess could just be setTimezone back to UTC).

Right now I'm leaning towards a trait, but I was hoping there was a better way to handle this. Maybe some way to have a $casts like variable defined in the model of which fields to convert to a user's timezone if set? Could that be done easily with a trait? I haven't used them that much.

0 likes
3 replies
martinbean's avatar

@jarcas I like to explicitly convert dates and times to the user’s preferred timezone with a method on the User model itself:

class User extends Authenticatable implements MustVerifyEmail
{
    public function convertTimezone(DateTimeInterface $dateTime): DateTimeInterface
    {
        return Date::instance($dateTime)->timezone(new DateTimeZone($user->timezone ?? 'UTC'));
    }
}
<dt>{{ __('Start date') }}</dt>
<dd>{{ $user->convertTimezone($event->start_date)->toDateTimeString() }}</dd>

If you need to do this for multiple models, then you could define and implement an interface, similar to Laravel’s built-in HasLocalePreference interface, and combine it with a trait to provide the actual implementation:

interface HasTimezonePreference
{
    public function preferredTimezone(): DateTimeZone;
    public function convertTimezone(DateTimeInterface $dateTime): DateTimeInterface;
}
trait ConvertsTimezones
{
    public function convertTimezone(DateTimeInterface $dateTime): DateTimeInterface
    {
        return Date::instance($dateTime)->timezone($this->preferredTimezone());
    }
}
class Venue extends Model implements HasTimezonePreference
{
    use ConvertsTimezones;

    public function preferredTimezone(): DateTimeZone
    {
        return new DateTimeZone($this->country->timezone);
    }
}
<dt>{{ __('Opens') }}</dt>
<dd>{{ $venue->convertTimezone($venue->opening_time)->toTimeString() }}</dd>
1 like
amitsolanki24_'s avatar

@martinbean

Can I add preferredTimezone() in trait also.


trait ConvertsTimezones
{

public function preferredTimezone(): DateTimeZone
    {
        return new DateTimeZone(auth()->user()->timezone ?? 'UTC');
    }
    public function convertTimezone(DateTimeInterface $dateTime): DateTimeInterface
    {
        return Date::instance($dateTime)->timezone($this->preferredTimezone());
    }

}

martinbean's avatar

@amitsolanki24_ That would defeat the entire point of having a trait you could use with multiple models, not just user models.

Please or to participate in this conversation.