I ran into trouble while dealing with date and time using php and mysql. I am trying to store local time of user's timezone as a timestamp on mysql db and would like it to convert back to normal date and time at the time of output.
This is the first time I am dealing with date and time.
As I understand: I can't rely on PHP's time() as it returns servers time according to server's timezone and the same case with mysql current_timestamp.
I can use the javascript to get user's local timezone and then can use date_default_timezone_set() for each session.
If I am doing right, now the confusion starts.
As you can understand the users will come from around the globe, so if two users (one from US and another from India) do something at the same time, will it show each others time as identical or it will show some difference? I mean it shouldn't show Indian user that the US user has done something few hours ago as the US user done at same time.
Please let me know if I don't understand these things properly.
What I want to achieve is, the output of the time should show in local time format. Ex: any time should show in IST format for Indian user and other country respectively.
Best way to achieve this is to store date in a database in a standard format (eg. GMT).
After getting user's timezone through javascript, you may convert date to user's timezone & display accordingly.
I have spent the last two days reading up on this and ultimately have ended up just as confused as when I started. I know the question has been asked many times before but I seem to be getting nowhere fast.
The problem is there seems to be such a wide variety of recommendations and differing advice given all over the web, including here on Stackoverflow.
So, I was hoping someone could set me straight once and for all.
Given that I have full control over both the server and the code, what is the best method to ensure that when a user performs a certain action the correct date/time is stored in the database and that any users from other timezones also get the correct time returned, relative to their timezone.
i.e. User A in France posts a comment, he sees the correct time returned when viewing that comment. User B in America view user A's comment and sees the time it was posted corrected to his timezone.
I need to know the best method to store the date/time in mysql and the best method to retrieve this date and display it correctly for any given client wherever they are in the world.
I am using PHP 5.3 and mySQL 5.5.
Thanks in advance!
You can store the date in UTC:
$utctime = gmdate('Y-m-d H:i', date('U')); // get timestamp and convert it to UTC
and display to user with his offset, you can ask him what timezone he has or you can try to get it, using AJAX or based on his IP.
Let's say his timezone is +7 hours:
$usertime = date('Y-m-d H:i', strtotime($utctime)+(7*60*60));
you can store as timestamp: $utctime = gmdate('U', date('U'));
I plan to capture the start and end of user initiated activities on my website using time() in php. I'm not sure if this is the best way to capture start/end times. Anyway, the data will be stored in MySQL, but again I'm not sure what datatype I should use.
Based on the answers I've read on stackoverflow, the datatype used depends on the purpose of the application.
Purpose of the application
At it's simplest, I want to record start, stop (and duration) of an
activity. Probably using time().
At it's most complicated I'd like to plot statistics based on when
the user did a certain activity, how much time they spent doing the
activity (in total), and when they were the most successful/least
successful etc, etc. (all based on the start/end times) Something to
keep in mind. The users will be from all over the world.
MORE INFO
If an activity is repeated a new record will be made for it. Records will not be updated.
At first, I had planned on storing unix timestamps in MySQL (as an integer datatype?), but from what I understand this is a bad idea, because I will lose a lot of MySQLs ability to process the information. If I store the information as DATETIME, but then move the server, all the times will change based on the local time of the server. Something I found confusing was that TIMESTAMP in MySQL is not the same as a unix timestamp- which is what I would be getting if I used time().
I'm aware that the unix timestamp can only hold dates up to 2038 for some systems, but that isn't a concern (at the moment).
Question: Should I use time() to capture start and end times for user initiated activities? Based on the purpose of the application, what datatype should I use to store the start and stop of user initiated activities?
THANKS
Thanks for the answers everyone. TBH I'm not convinced either way yet, so I'm still doing some research. I chose the TIMESTAMPS option because I really would like to store my information using UTC (GMT). It's a pity though that I will lose out on some of MySQLs inbuilt time functions. Anyway thanks again for your answers.
If you're going worldwide, MySQL's TIMESTAMP is almost universally a good choice over DATETIME, since it stores the time as UTC instead of local time so DST changes won't cause you problems if analyzing in multiple time zones.
Having a non DST changing time zone as a base can be a life saver, converting between multiple time zones with different DST changeover dates can really cause problems, consider for example having a timestamp during the hour that happens twice in a change from summer- to winter time.
Use DATETIME to store the time and use date('Y-m-d H:i:s') to get the current time to store it. When you fetch this value, you will get the time in this format.
To convert it to a timestamp, use $timestamp=strtotime($fetchedValue) To display this in another format use date('H:i',$timestamp). Read about formats from date manual of php
TIMESTAMP can only store values after Jan 1 1970, since it stores timezone data.
So if you are trying to store a date before Jan 1 1970, its better to use DATETIME.
Frankly, TIMESTAMP is useful only if you are actively syncing raw data between two machines with different timezone
How should I go about dealing with timezone. Is it safe to just store the offset for the user? Or should I also have the Area/Location? When I compared the offset values in Wikipedia and PHP, some doesn't match. Which should I trust?
Lastly how should I go about with it in PHP. Can I just do a "Time - Server Offset + User Offset"?
Area and location is important if you care about retaining all the data. The best way (in my opinion) to store dates is to store a UTC timestamp + the location.
Just the offset may be enough for certain calculations, but it could not be enough if you have a timestamp, and want to know the exact time for something like "+1 day". As this varies in different countries with different rules for daylight savings time.
So if you want to be absolutely certain you are not 'losing information' and unable to do time-based calculations in the future, store the UTC timestamp and the olson id (e.g.: Europe/Amsterdam).
To answer your second question, if you have these two pieces of information, you can easily reconstruct it with DateTime:
$dt = new DateTime('#' . $timeStamp);
// Now convert it to the users timezone
$dt->setTimeZone(new DateTimeZone('Europe/Berlin'));
// Now you have a 'DateTime' object which you can easily display with the ->format function.
Addition
I personally prefer to store timestamps as integers. The TIMESTAMP type does automatic conversion, and I feel it's better to let the PHP application handle this, this makes especially sense for what I think your use-case is (simple localization for users).
Using DATETIME works too, but the storage requirements are much higher than just using an integer. If you do prefer DATETIME, try to make it a rule within your application to store every value always as UTC, as there is never any confusion especially in relation to DST transitions and law changes in your local timezone.
If you simply want to show times on your web application calculated based on the users' local timezone, the offset is useless. The offset changes twice a year for most countries, and almost every year one or two country changes when this happens.
You only need the location if you use PHP's awesome DateTime and DateTimeZone objects.
A last bit of advice:
People tend to confuse dates and times in PHP applications and sending around these values in many different formats (strings, ints, etc) and mix GMT and UTC. Try to make it a rule for yourself to only ever send around DateTime objects in function arguments and return values, so you can typehint and there is never any doubt in what format a variable is in. It will be worth it.
You can save the timezone in the database as string using a dropdown menu filled with the timezones
When the user login save the timezone in a $_SESSION['timezone'] variable and set the timezone in your scripts like this:
date_default_timezone_set($_SESSION['timezone']);
You mention a user. I suggest you let the user selects his/her timezone and you store that in your database.
Here is how to synchronize PHP (>=5.3) and MySQL timezones per session and user settings. Put this where it runs when you need set and synchronized timezones.
date_default_timezone_set($my_timezone);
$n = new \DateTime();
$h = $n->getOffset()/3600;
$i = 60*($h-floor($h));
$offset = sprintf('%+d:%02d', $h, $i);
$this->db->query("SET time_zone='$offset'");
Where $my_timezone is one in the list of PHP timezones: http://www.php.net/manual/en/timezones.php
The PHP timezone has to be converted into the hour and minute offset for MySQL. That's what lines 1-4 do. The query line is using the Code Igniter framework, which you may not use, but the the query is show in the parentheses.
If you are dealing with the MySQL you can use the time zone information from (mysql_tzinfo_to_sql) it will automatically identify the users time according to the time zone.and you have to create a column of type timestamp that stores the users timezone information.
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');