Search code examples
phplaraveltimezonemiddleware

Timezone middleware does not work


I created a middleware in order to set the timezone based on the auth user timezone set in the database:

<?php

namespace App\Http\Middleware;

use Closure;

class TimezoneMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->user()->guest()) {
            $timezone = config('app.timezone');
        }
        else {
            $timezone = $request->user()->timezone;
        }

        date_default_timezone_set($timezone);

        return $next($request);
    }
}

I added this class to the bottom of the global HTTP middleware declarations in Kernel.php.

The problem is that it does not work. When displaying a created_at field, the time stays exactly the same no matter what I set the user timezone in the database.


Solution

  • I'd highly reccommend leaving your dates within the database in UTC - it'll save you headaches later on down the line.

    What i'd suggest is using Eloquent Mutators, which can be applied to your model(s).

    This will enable you to still use data tables as the mutation happens just after the data is pulled from the database.

    You could perhaps create a re-useable class within your application that has a static method on for parsing the date, for example:

    <?php
    
    namespace App;
    
    use Carbon\Carbon;
    
    class DateTimeZoneMutator
    {
    
        public static function mutate($value)
        {
    
            if (auth()->user()->guest()) {
                $timezone = config('app.timezone');
            }
            else {
                $timezone = auth()->user()->timezone;
            }
    
            return new Carbon(
                $value, $timezone
            );
    
        }
    
    }
    

    Then from within your model, for sake of argument lets presume your date field is called "registered_at", you'd add the following method:

    <?php
    
    namespace App;
    
    use App\DateTimeZoneMutator;
    use Illuminate\Database\Eloquent\Model;
    
    class Something extends Model
    {
    
        // ...
    
        public function getRegisteredAtAttribute($value)
        {
            return DateTimeZoneMutator::mutate($value);
        }
    
        // ...
    
    }