June 30, 2024
I recorded my first tip video for the good people at Laravel News. Enjoy!
Some favorites in America: eight in Indiana, three in North Dakota, twelve in Argentina, but I'm partial to America/Chicago. They come from timelib, which uses tz maintained by the Internet Assigned Numbers Authority. And honestly? tz
is a pretty fascinating Git repo. Read this narrative about Indiana or Metlakatla and you really can appreciate the work that goes into our open source infrastructure.
So weirdness and esoteric open source history aside, let's talk some tips about timezone handling.
I can't overstate enough that you really need to store datetime data in UTC. It might be tempting to use your local application timezone, until your timezone changes for some reason, or a database config is different in a new environment, or you want to support users in a different timezone - you're in pain. So from the outset, use UTC. This is the default in Laravel and it's very sensible.
If there was ever a time to use someone else's code, this is it. Please do not invent your own time zone handling support. In Laravel, that means that we're working with a package called Carbon, which can do a lot of things with dates and times, can do comparisons and math, convert between formats, and easily handle time zones.
I like to register a Carbon macro to make it easier to convert timezones from UTC to the application timezone.
1// config/app.php: 2[ 3 'timezone_display' => 'America/Chicago', 4]; 5 6// AppServiceProvider.php: 7public function boot(): void 8{ 9 Carbon::macro('inApplicationTimezone', function () {10 return $this->tz(config('app.timezone_display'));11 });12}13 14// Application code:15return $model->updated_at->inApplicationTimezone();16 17// a Blade view:18{{ $model->updated_at->inApplicationTimezone()->toDateString() }}
If you want to allow your user to set their timezone, be sure to store it as the PHP time zone string. Let's assume you have a $user->timezone
attribute:
1// AppServiceProvider.php: 2public function boot(): void 3{ 4 Carbon::macro('inUserTimezone', function () { 5 return $this->tz(auth()->user()?->timezone ?? config('app.timezone_display')); 6 }); 7} 8 9// Application code:10return $model->updated_at->inUserTimezone();11 12// a Blade view:13{{ $model->updated_at->inUserTimezone()->toDateString() }}
While researching for this video I came across DateTimeZone::listIdentifiers
which is a handy way to grab all timezone identifiers (e.g. America/Chicago) recognized by PHP. You can scope it down by timezone group (roughly by continent) and country code.