Laravel timezone – important settings
I would like to share one situation that I had while working on one of my projects and how timezone had effect on this.
Project I was working now was about synchronysing data between two applications. Data was synced in raw format which means completelly same values for fields like created_at and updated_at columns will be transfered.
After finishing synchronisation scripts and putting this in production and running first syncs, I’ve noticed that I have small difference in synced tables. I was syncing whole day data. At first it was tricky to notices because when I was filtering for example by category I had same number of records, but total for that day was different in few items, maybe less then 100.
This pointed me have a look at created_at fields because data was synced based on this fields. Synchronisation was done each day for previous day. Some of the records goes to next day because value in created_at column was different then in original table. Difference was actually one hour.
First thing that came in my head was to have a look at timezone in both projects, also both projects were Laravel apps. In first project timezone was Europe/Belgrade, while in second was UTC. The problem was with settings in first application where timezone was Europe/Belgrade.
So, what actually happened?
Laravel is asuming that all data saved in database is in UTC. When reads data from database if timezone is not UTC it will convert to timezone that is in your config/app.php file, in this case +01:00 for Europe/Belgrade.
Why is this bothering me? When we are saving data via Laravel models, it doesn’t convert to UTC even if timezone setting is differently set up. I belive that this logic is inconsistent and that logically consistent behaviour would be:
// If app.timezone = 'Europe/Belgrade'
// When WRITING:
Carbon::now() → 14:00:07 Europe/Belgrade
Convert to UTC → 13:00:07 UTC
Save to DB → 13:00:07
// When READING:
Read from DB → 13:00:07
Assume UTC → 13:00:07 UTC
Convert to app.timezone → 14:00:07 Europe/Belgrade
Perfect match!
Or alternatively:
// Treat app.timezone as database timezone consistently
// When WRITING:
Carbon::now() → 14:00:07 Europe/Belgrade
Save to DB → 14:00:07 (as Belgrade time)
// When READING:
Read from DB → 14:00:07
Assume app.timezone → 14:00:07 Europe/Belgrade
No conversion needed!Also, this can be resolved by adding method serializeDate in model. In that case when reading data laravel will not assume that data is saved in UTC, it will took timezone from your config/app.php file.
protected function serializeDate(\DateTimeInterface $date)
{
return $date->setTimezone(config('app.timezone'))->format('Y-m-d H:i:s');
}Anyway, few hours of investigation and work with Laravel timezone. 🙂