vlauciani's avatar

L5 - Best way to get user timezone

Hi all

Which is the best way to get user time zone? php or javascript? I've Date stored in UTC format in the DB and I'd like to print Date according to user time zone. What is the best way?

Thank you.

0 likes
10 replies
Kryptonit3's avatar

I would say make a setting for them to choose a php approved timezone then just use carbon to show the DB timestamps in their timezone

$myobject->created_at->timezone($this->auth->user()->timezone);

If it is created_at or updated_at then it will be a Carbon object. if you choose another column name be sure to add it to protected $dates on the model so it becomes a Carbon object and can be mutated.

protected $dates = ['my_custom_date'];

It's either ->timezone('mytimezone') or ->setTimezone('mytimezone')

Or do what I do on all my projects and don't mess with the headache of timezones and just show a friendly version like - 1 week ago, or 3 minutes ago with

$myobject->created_at->diffForHumans();

but again, needs to be carbon object.

4 likes
vlauciani's avatar

Hi

thank you for the answer but the problem is not to convert the dates stored into the DB to the user timezone... the problem is to get the user "timezone" from the browser request. In others words, when a user visits my site, I'd like to get his timezone; should I do it using javascript?

kjdion84's avatar

I did this by following these steps:

  • Create a migration adding a timezone string column in the users table with a default of config('app.timezone').

  • Add a <select> in your user updating forms:

<select name="timezone" id="timezone" class="form-control">
    @foreach (timezone_identifiers_list() as $timezone)
        <option value="{{ $timezone }}"{{ $timezone == old('timezone', request()->user()->timezone) ? ' selected' : '' }}>{{ $timezone }}</option>
    @endforeach
</select>
  • Add timezone to $fillable in the User model. My user profile controller uses fill() in order to update the users info via all().

  • Make the validation rule required|timezone for this field.

3 likes
willvincent's avatar

https://momentjs.com/timezone/

moment.tz.guess() will attempt to get the timezone name from the client browser.

The most foolproof method is to have the user manually set their own timezone.

EDIT: Damn, old thread. @kjdion84 Why are you reviving all these old threads?

1 like
kjdion84's avatar

Sorry for ressing this thread, but using momentjs does not mutate the time strings to their appropriate timezone when selecting data via relationships.

Yamen's avatar

I've displayed the the local time by saving the timezone in session variable with help of moment.js, here is the steps:

1 - use momentjs cdn (or with npm as you like)

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.0/moment.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.13/moment-timezone-with-data.js"></script>

2 - In login.blade.php make a hidden input within login form

<input type="hidden" name="timezone" id="timezone">

and push this script

var timezone = moment.tz.guess();
$('#timezone').val(timezone);

now we have a timezone variable in the login request.

3 - We'll access this variable in AuthenticatesUsers trait in LoginController, override the authenticated method in the controller

/**
     * The user has been authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  mixed  $user
     * @return mixed
     */
    protected function authenticated(Request $request, $user)
    {
        session(['timezone' => $request->timezone]); // saving to session
    }

4 - Finally to view any date as local time just add

$date->timezone(session('timezone'));

Note: Make sure that $data is a Carbon instance, otherwise you'll get using timezone method on string error, in this case just parse it Carbon::parse($date)->timezone(session('timezone'));

10 likes
ardianck's avatar

@Yamen, that works, one thing though, we should not modify the trait AuthenticatesUsers instead override the method in LoginControllerdirectly.

Please or to participate in this conversation.