Symfony 2.6+ User Timezones

If you’re displaying dates in Twig templates, you have probably thought to yourself, “Wouldn’t it be nice if they were displayed in the user’s own timezone?”.

I’ll use Symfony 2.7 framework, the FriendsOfSymfony User Bundle, and jstimezonedetect library. I’ll be basing this guide on Symfony 2.1 User Timezone by Thomas Huong, modified for the post 2.3 (no token in kernel.request) and 2.6 (security services split) which break the code they show. Credit really goes to them, and to Johnny Robeson, without whom I would have been lost.

Set default Timezone

You’ll want your backend code to always store time in UTC, since you don’t know what timezone your user will be in. You’ll want to do this as early as possible in your application execution, in our case the best place would be in the __construct  method of your AppKernel. You’ll most likely have to add the method yourself.

app/AppKernel.php

Some older documentation mentions the init method, but this is deprecated. Good alternatives is at the top of your entry script if not using the full framework, like app.php or app_dev.php. You can also set your timezone in your php.ini, but you may not have control of where your application is installed in the future.

Add the User TimeZone field

Add a field to your User class to store the user’s preferred timezone. In this case the User class provided by FOSUserBundle.

src/AppBundle/Entity/User.php

Make sure that you update your database with the new field.

Detect User TimeZone

An optional step for sure, but a cute one. You can use the javascript library jstimezonedetect to detect the user’s timezone, then update your database with it when the user logs in. Add some jquery code to your login page, most likely by overwriting the app/Resources/FOSUserBundle/views/Security/login.html.twig  to include a new javascript file called signin.js.

web/js/signin.js

This will add the user’s timezone as a hidden field in the login form. Next we’ll need to let Symfony know we want to hook into an event in services.yml, which will fire each time a user successfully logs in.

app/config/services.yml

src/AppBundle/EventListener/UserSubscriber.php

If you’re feeling particularly adventurous, you can look into rewriting the dates using jquery on the fly in the user’s detected timezone, but that is not covered in this guide.

Set the default Twig Timezone

Next, we’ll want to set a default timezone for the users of your site. Thankfully you can do this in your configuration files.

app/config/config.yml

Use User Timezone in Twig

Finally, we’ll want Twig to use the User’s timezone if they are logged in. We’ll want to change the Twig default timezone programically before your Controller is called. This has several advantages to a Twig Extension, which would force you to use a custom Twig function, this just overrides the default behaviour.

app/config/services.yml

src/AppBundle/EventListener/TwigSubscriber.php

Now whenever we render a date in Twig while logged in, it will use our User timezone instead of the default one we configured, but only if the user has one configured.

In older versions of Symfony prior 2.3, you could have subscribed to the kernel.request , however it no longer has the user token populated, hence subscribing to the kernel.controller  event instead, which occurs after the token exists. Prior to 2.6, you would use the security.context instead of the TokenStorageInterface as well.

If you prefer to view the code on github, see the gist or the complete solution implemented in the AskMyriam project.