Worrying about and working with timezones is always an absolute nightmare. With Laravel, it's not awesome, but it's a tad less painful.
The timezone select form, and the helper conversion functions used in this post are avaliable in a Packagist package. To include it in your project, follow the installation instructions on the github page. It'll only take you two minutes. The rest of this post will utilize the package.
Setting up the Database
First things first, decide on a uniform storage timezone. To keep things simple, for my project, I chose UTC (the package camroncade/timezone
also assumes you are using UTC). In Laravel, this is the default timezone out of the box, but it's good to double check.
// app/config/app.php
'timezone' => 'UTC',
Now, the date()
function will operate in the UTC timezone. This is ideal for this setup, because all dates stored in the database will be UTC.
Go ahead and add a column to your user table (or wherever you want to store the user's timezone setting) that can accept a string.
// migration.php
public function up()
{
Schema::table('user', function(Blueprint $table)
{
$table->string('timezone')->nullable();
});
}
I need users to be able to set their own timezone, but I also don't want to hand type all the timezones out into a select form. The package camroncade/timezone
includes an array of all the timezones, as well as a helper function that will build the select form option for us.
Timezone::selectForm();
This will output a simple select form, with the ID of each option the PHP-readable timezone.
The function selectform()
accepts four optional parameters, the first is the ID of the option you want selected. The second is a placeholder attribute, which I just leave as null. The third are any attributes you want to attach to the select tag such as name, class, style, and the fourth parameter is for attributes, if any, that you want to attribute to the option tags.
For a simple select form with Twitter Bootstrap styling, I used the following:
Timezone::selectForm('', null, array('class' => 'form-control', 'name' => 'timezone'))
Because the ID of the keys are the PHP-readable timezones, you can simply save to the database exactly what you grab out of the input.
Displaying and Storing Times
The package camroncade/timezone
also includes two helper functions that deal with timezone conversion. The functions are convertFromUTC()
and convertToUTC()
. We can use these when displaying and storing dates and times. Both functions accept three parameters, the third being optional.
The first parameter is the timestamp for the time you wish to convert. It accepts datetimes in the format Y-m-d H:i:s
. This is the format that Laravel, by default, stores created_at
and updated_at
.
The second parameter is the timezone you are converting to/from. If you used the select option builder in the package, the value you stored in the database will work here.
The third, and optional, parameter is the format you want to the datetime to be exported. Be default it is Y-m-d H:i:s
, but of course you can change this to what you want.
From here, anytime you want to display a time to a user, simply convert the timestamp from the database into their timezone using the provided functions. Here is an example of my use of this function:
Timezone::convertFromUTC($session->created_at, Session::get('timezone'), 'F j, Y')
Now, I like to store the users timezone of choice in a session when they login, that way I don't have to query the database everytime I want to display a time. The drawback to this is that if the user updates his timezone, you need to also remember to update the value you stored in the session as well.
I'm not sure if this is the best way about going about dealing with timezones, and this is certainly not the only way, but this is what seems to work for me.