I've just finished my first PHP application that had to handle dates and time spans correctly across multiple timezones and I thought I would share a couple of the things that I learned.
Store Everything in GMT
My first piece of advice is to store EVERYTHING in Greenwich Mean Time (GMT). The reason for this is that if you try to store datetimes in the timezone that the user is operating in it's going to cause problems when you try to aggregate data for that day in a different timezone. You'll have to create code to check for each timezone individually. Fortunately, GTM isn't too difficult to manage because PHP and MySQL both have functions that make it easy to work with (more on that later). You will have to do a lot of conversions from user time to GTM but it's not terribly difficult if you create a helper function in your user model.
Today isn't Always Today
In my application I had to deal with a lot of time spans. Specifically, I was looking at what events occurred in the user's local timezone during a specific day. This doesn't sound complicated but it really is when you factor timezones into the mix. Today in Eastern Standard Time is actually part of today and three hours of yesterday in Pacific Standard Time. This caused a lot of logic where I defined what 'today' is based on a time range like 2013-03-01 05:00:00 GMT to 2014-03-02 05:00:00 GMT (this is one 'day' in EST expressed in GMT).
Daylight Savings Time Sucks
This is due to the crazy rules due to Daylight Savings Time (DST). In the same timezones, the rules for DST can vary from country to country, at the state and county levels, and change depending on the year (us American's will remember the DST start and end dates changed recently). This is why you'll get the crazy list of timezones that PHP has listed in their List of Supported Timezones.
I highly recommend using these timezones as the user's timezone of choice and then use the functions below determine if the user is currently under DST and what their offset is.
$tzId is the Timezone name for the user's timezone.
Being an American I assumed that all timezones offsets were integer values. It turns out that there are actually some timezone that operate on half hour changes and even two that offset by 45 minutes. I have a hard enough time working with people in Mountain Time so I can't even fathom working with someone that has a non-integer hour offset. :-)
This really shouldn't affect your program if you're calculating the offset using seconds but just realize that this can happen and it's a total mind F when you see it. :-)
Timezone Specific Functions Suck
PHP is really build to make dates and times easy to work with but I ran into a couple problems when I moved my code from my development VM (set for a timezone of GMT) to my client's server (set to EST). This was because (like most things it made sense in hindsight) the PHP
strtotime() functions all operate in the timezone specified by the date.timezone setting in php.ini.
So you don't repeat my mistakes here is how to fix these problems before you have them.
gmdate() instead. It uses the same formatting options as
date() but it creates GMT based strings.
I haven't been able to find a direct replacement for this function but you can use
gmdate('U') instead to get the same result.
This can be used normally except you will need to append GMT to all your strings. So instead of having:
strtotime('2012-03-01 01:23:45'); strtotime($somedate);
You would need to write:
strtotime('2012-03-01 01:23:45 GMT'); strtotime($somedate . ' GMT');
Because my application logic knew what timezone the current user was located in I stayed away from doing any time manipulation using the MySQL functions. I did however need to insert timestamps occasionally and found that
utc_timestamp() works well.
Enjoy and let me know your experiences in the comments below.
Scott is the Director of Technology at WeCare Connect where he strives to provide solutions for his customers needs. He's the father of two and can be found most weekends working on projects around the house with his loving partner.
- Working With Soft Deletes in Laravel (By Example)
- Fixing CMake was unable to find a build program corresponding to "Unix Makefiles"
- Upgrading to Laravel 8.x
- Get The Count of the Number of Users in an AD Group
- Multiple Vagrant VMs in One Vagrantfile
- Fixing the "this is larger than GitHub's recommended maximum file size of 50.00 MB" error
- Changing the Directory Vagrant Stores the VMs In
- Accepting Android SDK Licenses From The OSX Command Line
- Fixing the 'Target class [config] does not exist' Error
- Using Rectangle to Manage MacOS Windows