I am currently studying the best way to handle timezones on my website. People from many different countries will access it simultaneously, and I have to show them time-based information, so I thought:
Store every time on database according to my server (same timezone, defined by PHP)
Then, the user has the option to choose his timezone, and I do the needed conversions by using mysql function DATEADD.
This seems to work fine, but my questions are:
Is this the best way?
Is DATEADD the most efficient function to handle the hour difference?
Thanks.
As described in MySQL Server Time Zone Support:
The current session time zone setting affects display and storage of time values that are zone-sensitive. This includes the values displayed by functions such as NOW() or CURTIME(), and values stored in and retrieved from TIMESTAMP columns. Values for TIMESTAMP columns are converted from the current time zone to UTC for storage, and from UTC to the current time zone for retrieval.
Therefore, if you use TIMESTAMP type columns, MySQL will handle timezone conversion for you automatically: just set the appropriate timezone for the session in its time_zone variable.
You are thinking in the right direction.
I would not use the server's timezone. Instead, use Coordinated Universal Time (UTC) time. It is the World Time Standard. This is pretty much the same as Greenwich Mean Time (GMT). Note that UTC does not change with Daylight Savings Time.
TO use in PHP see: http://php.net/manual/en/function.gmdate.php
From here, you can either add hours via: http://www.php.net/manual/en/datetime.add.php
Or set the timezone based on the users preference: http://www.php.net/manual/en/datetime.settimezone.php
The one you use is based on how you get the user's timezone. If you ask them for it (most accurate) you can set the timezone in PHP with the user selecting from a combo box. If you get it from the header with JavaScript using getTimezoneOffset(); then it is best to add hours based on the timezone offset.
I personally set all the times in my DB according to the GMT +0.00 timezone. So I use UTC_TIMESTAMP() (or UTC_DATE(),UTC_TIME() - whichever applies) when I want to add the current time, for example. This is server independent so I'm confident that even if I change my server I will not need to worry about this issue in the future.
Then the options are, if your visitors have a chance to pick their own timezones, you can use the DATE_ADD() and DATE_SUB() functions to format the result before providing results.
Otherwise if you have the chance (this is my favorite solution) you can use Javascript to format that date/time, which you can make it handle easily by something like
function getLocalDate(dt) {
var d = new Date(0);
d.setUTCSeconds(dt);
return d.toLocaleDateString();
// or in some format that you choose
}
which gets the date echoed by PHP using strtotime($row['some_date']);.
Related
I am working on codeigniter application which have users from different time zones. Each user has some notifications based on some dates calculation.
So what should be best way to store date into Mysql? Either timestamp or datetime?
First off, you need to be aware of the locale setting for your mysql server. You want the server to be set to use UTC as a neutral setting. Any data that is stored in the mysql server will be relative to the server's timezone setting.
Unless you are dealing with future data (beyond the year 2032) or conversely really old data, the most efficient mysql datatype is the timestamp datatype. Just be careful to turn off the automatic mysql timestamp functionality when you don't want or need it.
Internally to PHP you want to utilize the DateTime class which includes ways to convert from any one timezone to another.
The missing ingredient that has not been mentioned, is that in order for this to work for end users, you need to store their timezone, or utilize functions in the browser to read from the operating system the current timezone of their workstation.
Timezone strings can be stored, and then used after you fetch data from the server, to then convert it and show it to them relative to their timezone.
But again to be clear, all data should be stored as UTC, and this requires that the server be configured to utilize UTC. Well it's a bit more complicated than that, but you can save yourself a lot of trouble when you insure there isn't a mismatch. By the same token your web/application servers (and in fact all servers) ought to be set to UTC, and of course to sync their time using NTP. Most cloud based servers are going to do this by default.
Format doesn't matter as long as you keep your date as DataTime Object. Using PHP you can easily manipulate dates. My personal choice is using UTC offset because is easier for debug purpose. You can easier figure out if your time difference calculation is correct looking on the offset then on time zone name.
More information you will find under DataTime class.
Implementation is basically the same regardless format as long as you are using DataTime Object. This is the best way to calculate time differences in different time zones.
With datetime you get a rich set of tools for interacting with the data (including converting between timezones) and the opportunity to handle dates prior to 1st Jan 1970 and after 19th Jan 2038.
Although the same tools are also applicable to TIMESTAMP, the automatic timezone conversion can get messy.
A further consideration is that TIMESTAMP also acquires some subtle timezone conversions which get rather messed up if you move to maxdb mode or back. Indeed, datetime data will be more portable across different systems.
It does not matter as long as you are using UTC value. However, timestamps are better way to store data from different timezones as it always represents and stored as the standard time(UTC) irrespective of the timezone of client/server.
But, as you are taking the data from user's input it does not make a difference.
For the accurate standard time(UTC), you just need to convert it right according to the user's timezone.
You can retrieve user's timezone either from browser headers(which is a less accurate method) or you can ask the user himself(using a input).
I have gone through many timezone/PHP posts, and most suggest storing your datetime fields in UTC, then using the application users timezone offset when storing and displaying datetime information.
The problem i have I've inherited an application that wasn't timezone aware, and now I need to cater for this.
The server is already set to "EST +11:00 Australia/Melbourne", and there are already applications running from that server. So i can't change this.
Fortunately, I do know a users timezone offset, ie -05:00, etc,.
The application takes Javascript Dates and parses them using PHP's strtotime() function and stores in a MySQL database, like this:
$event_starts = date('Y-m-d H:i:s',
strtotime('Thu Dec 02 2010 11:15:00 GMT+1100 (AUS Eastern Daylight Time)');
So does anyone have any suggestions for the best way on how I can make this application timezone aware considering the server isn't set to UTC?
Many thanks, J.
This is not going to be very easy.
First of all, consider that existing stored dates are in local time of your server, which observes daylight saving time. Any code that has to do anything with these dates except just printing them, now or in the future, will need to convert them to UTC first. If the daylight saving rules are not exactly the same at the point in time where the date was stored and the current time (when the conversion is taking place), your server will use the "current" rules and therefore produce a wrong result. Granted, this scenario may be far-fetched in your specific case (or then again it might not), but it's a very strong warning against storing anything other than UTC.
Assuming that the DST rules remain constant, and that you have PHP >= 5.3.0, you can do this:
Read "original" database date with DateTime::createFromFormat, explicitly specifying the timezone (server's TZ)
Convert to user local time with DateTime::setTimezone (specifying user's TZ)
Display to the user
When receiving user input, you will need to do the reverse:
Create user local time date with with DateTime::createFromFormat, explicitly specifying the timezone (user's TZ)
Convert to server local time with DateTime::setTimezone (specifying server's TZ)
Store in database
Apart from the above, I would suggest taking your application offline at some point and convert all dates in the database to UTC. You would then be rid of the problem discussed earlier (at least in the future, as the past cannot be undone). The "server's TZ" I mention above would then be UTC (regardless of the fact that the actual server may be set to AUS EDT or not, your "working" timezone will be UTC).
You could make use of
1) date_default_timezone_set - Sets the default timezone used by all date/time functions in a script
2) Instead of using this function to set the default timezone in your script, you can also use the INI setting date.timezone to set the default timezone.
The important thing to keep in mind is not UTC, but that all times stored must be standardized to one timezone. So, if your PHP server and your database server both use the same timezone, the only issue that arises is when you need to display a location-aware time to the user or when you allow a user to enter a datetime from another timezone.
PHP has a nice, though somewhat scantly documented class, called DateTime. And some ancillary classes like DateTimeZone, DateInterval, etc. These make converting from db time to user time pretty simple.
So does anyone have any suggestions for the best way on how I can make this application timezone aware considering the server isn't set to UTC?
If you manage to come with any scheme for remapping the timezones its going to be horribly complicated and even more impossible to ever fix properly. Do yourself a favour and get the server timezone to UTC and fix your existing data.
First of allyou have to convert the date time selected by user to timestamp.
You have to use Server time zone offset and save the time to server in GMT.
This is the best way because while displaying the date just add the offset of the user
and convert and show.
I have implemented this for my client as it was an auction site and user may add item from AUS in his time and bidder will be from US. Time zone issues was there and we implemented after a lots of rerence.
You know one thing best and easy way is , do like ebay . just save the user time zone and show time with the time zone. No conversion nothing. Simple and better . 10:35 EST :)
If you wannabe perfect in time zone conversion, think about daylight saving time also. start date and end date on each year will change slightly. If you want to be accurate you have to save the daylight starting and ending date in db and add that difference too .:)
For working with datetime in different timezones and formats you can try to use PHP library Dater (https://github.com/barbushin/dater). Cheers!
I have one website which does not use US timings. Is it possible to change PHP and MySQL timings for one website? If so what do I need to do?
you can do it per connection , when you start connection to this website set it,
look at :
http://dev.mysql.com/doc/refman/5.6/en/time-zone-support.html
#
Per-connection time zones. Each client
that connects has its own time zone
setting, given by the session
time_zone variable. Initially, the
session variable takes its value from
the global time_zone variable, but the
client can change its own time zone
with this statement:
mysql> SET time_zone = timezone;
but be aware that :
The current session time zone setting affects display and storage of
time values that are zone-sensitive.
This includes the values displayed by
functions such as NOW() or CURTIME(),
and values stored in and retrieved
from TIMESTAMP columns. Values for
TIMESTAMP columns are converted from
the current time zone to UTC for
storage, and from UTC to the current
time zone for retrieval.
The current time zone setting does not
affect values displayed by functions
such as UTC_TIMESTAMP() or values in
DATE, TIME, or DATETIME columns. Nor
are values in those data types stored
in UTC; the time zone applies for them
only when converting from TIMESTAMP
values. If you want locale-specific
arithmetic for DATE, TIME, or DATETIME
values, convert them to UTC, perform
the arithmetic, and then convert back.
an example how to set is in :
http://www.electrictoolbox.com/mysql-set-timezone-per-connection
For PHP:
<?php
date_default_timezone_set('Europe/London');
?>
See the list of PHP supported timezones here: http://www.php.net/manual/en/timezones.php
For MySQL you'll need to execute query like this:
SET time_zone = timezone;
See detailed information in the MySQL documentation: http://dev.mysql.com/doc/refman/5.1/en/time-zone-support.html
Yes, you should do all time zone conversions inside PHP, not mysql.
For each column in your database which stores a date/time, either
a) Store it in GMT and do the necessary conversion OR
b) Store it in local time always
In neither case does MySQL need to know, but your developers do so be sure that you document this in your schema if you have a mixture.
It is often necessary to store local time date/time values. MySQL does not remember a time zone in a datetime column (nor could it easily; other DBs attempt to in some cases).
If you are storing a precise point in time which has already happened (e.g. now) then you should always store it in UTC to avoid confusion about when exactly it happened. Some apps use epoch / unix time for this purpose.
A future time you may have to store in local time because you can't tell (yet) exactly what time it will have to happen, that may depend on the decision of politicans who might not have been elected yet.
Time zones are tricky things because politicians control them. They tend to change with little warning (typically only a few years)
I have just realised if I add a particular record to my MySQL database - it will have a date/time of the server and not the particular user and where they are located which means my search function by date is useless! As they will not be able to search by when they have added it in their timezone rather when it was added in the servers timezone.
Is there a way in Codeigniter to globally set time and date specific to a users location (maybe using their IP) and every time I call date() or time() that users timezone is used.
What I am actually asking for is
probably how to make my application
dependent on each users timezone?
Maybe its better to store each users timezone in their profile and have a standard time (servers time) and then convert the time to for each user?
Thanks all
It sounds like what you need to do is store all of the date and times in your system as UTC time (used to be called GMT). This is the base time that everything in the world is calculated off of with adjustments. (eg: Central Time is -6 hours off of UTC)
In MySQL you can use UTC_TIMESTAMP() to get the current UTC time as long as your server and DB are configured with the correct times and timezone settings.
In PHP run this to set the timestamp of PHP to UTC (you will run this in your code so put it on every page or in a centralized index file):
date_default_timezone_set('UTC');
Or you can go directly into PHP.INI and tell it to use UTC time globally. (this may not work if you have multiple websites on a single installation of PHP.
And then anywhere in the system you need to get the current UTC time you can just call:
time();
Then for each user in the system you will need to ask them what timezone they live in and then when you display times make the adjustment for that user. So if it is 5:00PM UTC and I live in Easter US (-5) the time would be 5:00 - 5 hours = 12:00PM.
This can be a long process to get right but once you do your users will find it very useful especially internationally.
I think the easiest way is define a timezone for internal data storage (your server's time zone or UTC) and convert the time according to the user's time zone when outputting it.
I don't know CodeIgniter so I can't point you to the right functions. One prominent library that is timezone aware is Zend_Date: Working with Timezones I have not worked with these functions yet but they look promising.
However, once you know the user's time zone, it's not difficult to put together an own function that adds/substracts the offset when outputting dates and/or times.
Possibly related question:
MySQL: keep server timezone or user timezone?
Take an example of an existing web application such as WordPress and phpBB. Each user have their own timezone setting.
When receiving a content from the user, use local_to_gmt() function in the Date Helper then save the content into database using the gmt date. When fetching the data you will get the time in gmt. Get the user's timezone setting, then display the data in that timezone.
This way, you can save yourself from calculating between two timezone. Just make sure that your server's time is in correct setting, so all your data is in the correct gmt time.
UPDATE:
Recently I review the last project I worked on that have timezone issue. After thinking various scenario, here is the solution for the timezone issue:
All data stored right now already
using server's time. Changing this
will takes times and prone to error,
so I leave it like that.
For the new data from user that set the content date to a certain
date and time, I stored it into 2
column. First column is to store the
data as is, and used to displaying
it as is. Second column will be a
recalculation of the date based on
the user's timezone into server's
timezone. This column is used in the
WHERE statement (filter based on
server date) and for the ORDER
(because this column's value all in
same timezone, which is the server's
timezone).
This way, I only do 1 timezone calculation, which is to convert user date into server date. For displaying , I display the date according to server's datetime. Since all data stored in the same timezone, data can be ordered by the column that hold the server date value.
For the user that have set their timezone, the date from database can be easily recalculated to get the datetime in the user's timezone. Btw, in my application, I display the date using timeago jquery plugins. This plugins need time in the ISO8601 format (UTC time). local_to_gmt() function in CodeIgniter can be used to do this.
Obviously the leap to British Summer Time (Daylight Savings Time) is a big confusion in the world of programming, and I am indeed caught up in that confusion.
The best possible solution I can find (which I will try to coherently explain) when using a timezone sensitive system is this:
The Web Server and Database should both be running off the same machine timezone. I suggest UTC as it is the building blocks of timezone conversions. This will ensure that all of the dates stored in your database are constant, and don't skip any times such as the 1hour jump between Daylight Savings.
At the top of all of your PHP scripts use date_default_timezone_set('Europe/London'); with the specific timezone of the user.
When producing dates from user submitted forms, use gmmktime(); to ensure that the timestamp created is UTC and not altered by the timezone that you have set.
date(); can be used when displaying dates, as this will convert the timestamp to the correct time taking into account the timezone that you have set.
If you do need to show a date in the UTC format then use gmdate(); with the $gm_timestamp that you have taken from the database or created with gmmktime();.
I have written this bit of PHP to help understand the situation.
date_default_timezone_set('UTC');
$gmtime = gmmktime(2,0,0,03,29,2009);
$time = mktime(2,0,0,03,29,2009);
echo $gmtime.'<br />'.date('r',$gmtime).'<br />'.gmdate('r',$gmtime).'<br />';
echo $time.'<br />'.date('r',$time).'<br />'.gmdate('r',$time).'<br />';
date_default_timezone_set('Europe/London');
$gmtime = gmmktime(2,0,0,03,29,2009);
$time = mktime(2,0,0,03,29,2009);
echo $gmtime.'<br />'.date('r',$gmtime).'<br />'.gmdate('r',$gmtime).'<br />';
echo $time.'<br />'.date('r',$time).'<br />'.gmdate('r',$time).'<br />';
Hopefully I've done a good job, but I doubt it because I'm still trying to battle the problem in my head.
UPDATE:
Glad I did this, because I am now having doubts about the user inputted dates.
To get the User inputted date (taking into account their timezone) to match up with the UTC corresponding date in the database, you should put it through mktime(). And then use gmdate('U', $timestamp); to get the true UTC timestamp. (I think)
Example
Looking at it from a reporting side, the user is using the 'Europe/London' timezone. At the start of our PHP script we call date_default_timezone_set('Europe/London');, whilst the Database (and all the records within) is still in UTC.
The user then sends through that they want to select a list of books added to the database between 25/03/2010 10:00 to 30/03/2010 14:00. The PHP script then runs the date variables through mktime($hour, $minute, $second, $month, $day, $year) to generate a correct UTC timestamp. The start date will not change, but PHP knows that the end date is within the BST timezone, so changes the timestamp to UTC accordingly.
When the results are returned back to the user, date('r', $date_added) can be used to show the user the date the book was added to the database according to their set timezone.
This link may help with understanding when it changes. http://www.daylightsavingtime.co.uk/
I think recalculating to user's time is better option, since it gives you normalized time on server, i.e. if you'll need to look up something, that happened (from your point of view) hour ago, you won't have a mess with american, asian and e.g. australian time.
Just ask them for their timezone (usually select with major cities in that timezone) and then recalculate :)
Or, alternatively, you can store two timedates - one for your comparison and one to show, so you won't have so much calculations on serverside.
Also, if recalculating, you can use date helper:
http://ellislab.com/codeigniter/user-guide/helpers/date_helper.html
I've used the MySQL built-in timezone conversion. In the database, all datetimes are stored as UTC. In the select query, I used CONVERT_TZ to convert to the user's timezone. You can specify timezone codes or hour invervals like:
SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET');
SELECT CONVERT_TZ('2004-01-01 12:00:00','+00:00','+10:00');
But, the problem is this does not accommodate for daylight savings times. This is particularly frustrating since many parts of the world either don't honor daylight savings or honor it on different dates. So, if you install the timezone description tables, you can use descriptive names that will account for daylight savings automatically like:
SELECT CONVERT_TZ('2004-01-01 12:00:00', 'UTC', 'US/Eastern');
Codeigniter contains a helper which deals with all manner of date functions.
Codeigniter Date helper
the command gmt_to_local() should help you... the third parameter is for 'daylight_saving'.
Takes a Unix timestamp (referenced to GMT) as input, and converts it to a localized timestamp based on the timezone and Daylight Saving time submitted. Example:
$timestamp = '1140153693';
$timezone = 'UM8';
$daylight_saving = TRUE;
echo gmt_to_local($timestamp, $timezone, $daylight_saving);
Add this line to autoload.php in the application folder/config folder:
$autoload['time_zone'] = date_default_timezone_set('Asia/Kolkata');
My server is in Dallas. I'm in New York City.. and both PHP and MySQL have configuration variables for setting the timezone.
How do I get them all to work together? What dates should I store in MySQL? How do I get PHP to handle changing the date based on the user's preference?
Bear in mind: I don't think I'm ever having PHP explicitly set the date, it's always using "NOW()" in queries.. however I foresee the need to do this. How would this be done?
I'm hoping SO's experience can help me out here.
Use Unix Time everywhere. It's using UTC so it's the same for every timezone. Methods for dates usually convert to it and back from it using timezone information they have, so you would have yourself a correct time.
Alternatively you could use Unix Time only to transfer time from one computer to another (like from DB to your server running PHP, or to JavaScript client). There's functions to convert to it and from it in every language. For MySQL it is:
UNIX_TIMESTAMP(date)
FROM_UNIXTIME(unix_timestamp)
That way you could have your time properly formatted on the DB and in logs but still have correct local time everywhere.
I prefer using dates and times in the native form with respect to the environment, that is, Unix timestamps in PHP and DATE/TIME/DATETIME/TIMESTAMP fields in MySQL. I translate both values into another using FROM_UNIXTIME() and UNIX_TIMESTAMP(). I prefer this instead of Unix timestamps, because native dates/times are much easier to read.
Record your dates in GMT (zero offset) and then calculate the offset based on the local timezone (EST is +6, for example, so you'd add 6 hours to the GMT).
Check the Date docs for the date_default_timezone_set() function.
Just remember, when writing to the database, you'll have to change time zones, store the date, then change back. Likewise, when you're retrieving the date, don't forget to add the timezone offset.
The mysql-server stores dates in a timezone independent format (UTC).
But before it stores the date it will be converted using its timezone.
U can change the mysql timezone per connection *1:
mysql_query('SET time_zone = "'.$timezone.'"');
You can also change the timezone per script.
date_default_timezone_set($timezone);
If you set them to the same timezone "2009-01-10 13:30:00" will mean the same thing to both mysql and php.
But keep in mind that the 2 servers have different internal clock values, so if you want to generate timestamps based on current time. Do that in mysql OR php.
*1)
MySQL timezone support may require additional configuration. check the manual