0

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.

kjdion84
  • 9,552
  • 8
  • 60
  • 87
  • All dates and times in the database are stored in UTC. Unless you do some sort of transformation that is what you will get back from a database query. – RiggsFolly Apr 24 '17 at 13:48
  • I just want any `timestamp` that is fetched from the database to use the user-specifed timezone. I've tried middleware, service providers, nothing works. I'm lost. I'm using datatables so I want this to be done automatically. – kjdion84 Apr 24 '17 at 13:49
  • You probably need to read this http://stackoverflow.com/questions/15017799/how-to-convert-utc-date-to-local-time-zone-in-mysql-select-query – RiggsFolly Apr 24 '17 at 13:56
  • 1
    Remember `date_default_timezone_set()` only effects what the PHP date and time functions do!!! – RiggsFolly Apr 24 '17 at 13:57
  • My question is really in regards to how to do this with Eloquent automatically on every query. – kjdion84 Apr 24 '17 at 13:57
  • Laravel doesn't care about `date_default_timezone_set`, it uses the value of `config('app.timezone')`. Replace that line with `config('app.timezone', $timezone)` and it will probably work. – ceejayoz Apr 24 '17 at 14:35

3 Answers3

2

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);
    }

    // ...

}
James
  • 532
  • 3
  • 14
0

Your question seems like you want normal filter/system middleware NOT route middlewares so if you put your middleware bottom of the kernel.php file that will not gonna work.

There is different middlewares in kernel.php, you should add filter type middle ware in $middleware section and if your middleware is for routes to protect the routes then add intorouteMiddleware`.

Filter type middleware as yours go into this

protected $middleware = [
    //.............
];

and if routes protection and filter middle ware goes into this

protected $routeMiddleware = [
    'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
    //..................
    //.................

];

and for time zone

Config::set('app.timezone','custom time zone');
BetaDev
  • 4,516
  • 3
  • 21
  • 47
  • I already put the class in the global HTTP `$middleware` declaration like I said in the OP. – kjdion84 Apr 24 '17 at 13:55
  • 1
    did you try to set timezone using `Config::set('app.timezone','custom time zone');` in stead of `date_default_timezone_set($timezone);` – BetaDev Apr 24 '17 at 13:55
  • why dont you just leave the time zone as it is and at the time of display format the date and time, have you looked into `Carbon` class – BetaDev Apr 24 '17 at 13:58
  • 1
    "The config timezone is set to UTC which is what the app needs to use when inserting timestamps into the database." As long as you're using proper `TIMESTAMP` fields in the database (not `DATETIME`), Laravel will always store as UTC regardless of what the config value is. – ceejayoz Apr 24 '17 at 14:39
  • Laravel uses the app timezone in order to determine what timestamp to insert into the database. See `Illuminate\Foundation\Bootstrap\LoadConfiguration`. – kjdion84 Apr 24 '17 at 15:04
  • @kjdion84 Laravel uses Carbon for timezone conversion. You can test this in just a couple minutes - set the app's timezone to something non-UTC, and save a date to a `TIMESTAMP` field. It'll be fine. – ceejayoz Apr 24 '17 at 15:20
0

You may use like:

{{ $model->created_at->setTimezone( $timezone )->toDateTimeString() }}

However, I believe there must be a better option.

kingvish
  • 1
  • 1