I'm in the early stage of building a mysql table that will hold data from two timezones. Both my machine and the server are in the America/Los_Angeles time zone. The timezone table is not loaded in the mysql server, but elsewhere on this site, I've read this is not necessary as long as php handles the queries - php will write the UTC offset to mysql. Mysql datatype is TIMESTAMP. Sample data has been inserted with a php script that includes the following statement:
if($company == 'HOS_CIN' or $company == 'HOS_FER') {
date_default_timezone_set("America/New_York");
}
Then two php scripts were used to display the data in a browser. One included the above statement and one did not. The one with the statement displayed the time as noon EST, and the one without displayed the time as noon PST. If mysql had stored the UTC offset, shouldn't there have been a three-hour difference in the times displayed?
Php version 5.3.3, mysql version 5.0.95
You have to face the following limits regarding PHP and MySQL:
MySQL does not have any column type that allows to store a local time with time zone information.
PHP cannot pass complex data types (such as DateTime instances) to MySQL, everything needs to be stringified, and MySQL doesn't have a syntax to pass a date literal with time zone information.
In practice it isn't as bad as it may seem because you don't normally need the local time of the user who inserted the information: you just need to know the exact moment in time the stored date refers to and (optionally) the time zone in which the stored date has to be displayed. And there're basically three sensible ways to do so:
Use a format that's unaffected by time zones, e.g. a Unix timestamp stored as INT.
Use a date column type with explicit time zone information, e.g. a TIMESTAMP column (not to be confused with Unix timestamps) where time zone is always UTC.
Use a date column type with implicit time zone information, e.g. a DATE or DATETIME column where you have decided that all dates belong to a given time zone, possibly UTC.
The difference between #2 and #3 is whether MySQL is aware of the time zone or it's something only you and your code know.
Whatever approach you chose, it's necessary that all the programs that are expected to do time zone conversions are instructed about what time zone to use:
PHP needs the time zone to generate/display Unix timestamps and to convert from/to the local time typed/expected by user and the one expected/printed by MySQL, e.g.:
$user_date = new DateTime('2016-10-03 00:00:00', new DateTimeZone('Europe/Berlin'));
$user_date->setTimezone(new DateTimeZone('UTC'));
echo $user_date->format('c');
MySQL needs the time zone when you use TIMESTAMP columns, to convert from/to the local time, e.g.:
mysql> create table foo(
-> foo int(10) unsigned auto_increment,
-> my_date timestamp,
-> primary key (foo)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> set ##time_zone = '+01:00';
Query OK, 0 rows affected (0.00 sec)
mysql> insert into foo (my_date) values ('2016-12-27 18:50:00');
Query OK, 1 row affected (0.00 sec)
mysql> set ##time_zone = '-07:00';
Query OK, 0 rows affected (0.00 sec)
mysql> insert into foo (my_date) values ('2016-12-27 18:50:00');
Query OK, 1 row affected (0.00 sec)
mysql> select * from foo order by 1;
+-----+---------------------+
| foo | my_date |
+-----+---------------------+
| 1 | 2016-12-27 10:50:00 |
| 2 | 2016-12-27 18:50:00 |
+-----+---------------------+
2 rows in set (0.00 sec)
mysql> set ##time_zone = '+09:30';
Query OK, 0 rows affected (0.00 sec)
mysql> select * from foo order by 1;
+-----+---------------------+
| foo | my_date |
+-----+---------------------+
| 1 | 2016-12-28 03:20:00 |
| 2 | 2016-12-28 11:20:00 |
+-----+---------------------+
2 rows in set (0.00 sec)
Related
Is there a way I can make a query in MySQL that will give me the difference between two timestamps in seconds, or would I need to do that in PHP? And if so, how would I go about doing that?
You could use the TIMEDIFF() and the TIME_TO_SEC() functions as follows:
SELECT TIME_TO_SEC(TIMEDIFF('2010-08-20 12:01:00', '2010-08-20 12:00:00')) diff;
+------+
| diff |
+------+
| 60 |
+------+
1 row in set (0.00 sec)
You could also use the UNIX_TIMESTAMP() function as #Amber suggested in an other answer:
SELECT UNIX_TIMESTAMP('2010-08-20 12:01:00') -
UNIX_TIMESTAMP('2010-08-20 12:00:00') diff;
+------+
| diff |
+------+
| 60 |
+------+
1 row in set (0.00 sec)
If you are using the TIMESTAMP data type, I guess that the UNIX_TIMESTAMP() solution would be slightly faster, since TIMESTAMP values are already stored as an integer representing the number of seconds since the epoch (Source). Quoting the docs:
When UNIX_TIMESTAMP() is used on a TIMESTAMP column, the function returns the internal timestamp value directly, with no implicit “string-to-Unix-timestamp” conversion.
Keep in mind that TIMEDIFF() return data type of TIME. TIME values may range from '-838:59:59' to '838:59:59' (roughly 34.96 days)
How about "TIMESTAMPDIFF":
SELECT TIMESTAMPDIFF(SECOND,'2009-05-18','2009-07-29') from `post_statistics`
https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timestampdiff
UNIX_TIMESTAMP(ts1) - UNIX_TIMESTAMP(ts2)
If you want an unsigned difference, add an ABS() around the expression.
Alternatively, you can use TIMEDIFF(ts1, ts2) and then convert the time result to seconds with TIME_TO_SEC().
Note that the TIMEDIFF() solution only works when the datetimes are less than 35 days apart!
TIMEDIFF() returns a TIME datatype, and the max value for TIME is 838:59:59 hours (=34,96 days)
I am building a PHP to MySQL webpage and I didn't notice it until now. My date from form field which is posted to PHP script is sent to MySQL table for storage. Even though in the date field within the form is being displayed correctly and POST date value is verified to be exact, it is not going into my MySQL table correctly. For some odd reason, the year is 2006 not 2012. However, the time is correct.
Here is my Form date field:
<input type=text id="date" name="srdate" value=<?php echo date("m/d/y"); ?>
Date Column in my MySQL table is of TYPE DATE.
I did check the date stored in my table and it has wrong date not year 2012 but 2006.
Any Idea,
MySQL's only acceptable date input format is YYYY-MM-DD HH:MM:SS. The date you're generating in PHP will look like (for today) 06/12/12 which MySQL will try to parse, but see as 12th December, 2006, and not the actual June 12/2012.
As well, note that your code is gaping wide open for SQL injection attacks. Read up and learn how to prevent those before you go ANY FARTHER with this code. Otherwise your server is going to get pwn3d.
You need to use the yyyy-mm-dd syntax.
While I'd expect MySQL to throw an error when trying to insert 06/12/12 it apparently parses it as 2006-12-12:
mysql> SELECT cast('06/12/12' as date);
+--------------------------+
| cast('06/12/12' as date) |
+--------------------------+
| 2006-12-12 |
+--------------------------+
1 row in set (0.00 sec)
mysql> SELECT cast('2012-06-12' as date);
+----------------------------+
| cast('2012-06-12' as date) |
+----------------------------+
| 2012-06-12 |
+----------------------------+
1 row in set (0.00 sec)
From the manual:
Although MySQL tries to interpret values in several formats, date parts must always be given in year-month-day order (for example, '98-09-04'), rather than in the month-day-year or day-month-year orders commonly used elsewhere (for example, '09-04-98', '04-09-98').
I allow my users to add events to my webapp. Users can originate from all around the world.
My current idea is to determine the user's time zone automatically (using an IP to location API) and insert it into the users table (I will also allow them to change it).
On the events table I will insert the event start date/end date in UTC.
Then, whenever I need to display the event info, I would take the event start date/end date from the table and do the calculation against the user's timezone.
Is that considered as good practice or is there a better way to do that?
Anything I should be aware of when doing this?
Thanks,
Yes, that is indeed a good way. Also keep in mind that if you use the TIMESTAMP type in MySQL, MySQL handles the timezone converting for you. When you insert new dates/times to the database, MySQL converts it from the connection's timezone to UTC (TIMESTAMP is always stored in UTC). When you retrieve a TIMESTAMP field from database, MySQL converts it back to the connection's timezone.
So if you use TIMESTAMP fields in MySQL, all you need to do is tell the user's timezone to MySQL at start of each your page. You do so by:
SET time_zone = 'Europe/Helsinki'
You can also use numeric timezones:
SET time_zone = '+02:00'
Keep in mind that you might need to install the tzinfo to MySQL first, which is trivial though (only for the non-numeric version though). Here's information about how to do it: http://dev.mysql.com/doc/refman/5.0/en/mysql-tzinfo-to-sql.html
In a nutshell, this is the important part:
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql
Here's an example of how it works:
mysql> CREATE TEMPORARY TABLE test(foo TIMESTAMP);
Query OK, 0 rows affected (0.00 sec)
mysql> SET time_zone = '+00:00';
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO test VALUES ('2011-02-03 16:00:00');
Query OK, 1 row affected (0.00 sec)
mysql> SET time_zone = '+02:00';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT foo FROM test;
+---------------------+
| foo |
+---------------------+
| 2011-02-03 18:00:00 |
+---------------------+
1 row in set (0.00 sec)
If you don't use TIMESTAMP field, eg. you use DATETIME (which also supports wider range of dates), then you just need to make sure you always insert dates in UTC; I do this by always setting connection's timezone to +00:00. Then you can have a view helper in PHP that converts the datetime to the user's timezone, which is quite trivial to do with PHP's DateTime class and setTimezone function. There's an example in the last link. To use this method, you must make sure PHP is also set to use UTC as its default timezone, which you can do with this:
date_default_timezone_set('UTC');
Whichever method you use, you should always be aware of these facts:
The PHP and MySQL connection's timezones should always be set to the same value so they're consistent with each other
Generally it's a bad idea to mix TIMESTAMP and DATETIME types with each other
If you use TIMESTAMP type, set the timezone to the user's timezone
If you use DATETIME type, set the timezone to UTC and handle timezone convertions in PHP
Few thing I would consider:
Provide the users the means to set the time zone manually.
Assuming your users may change their location, let them specify the time zone for the event they add (or the location if you can get the time zome from that).
This way hopefully they won't miss anything :) Good luck with your webapp!
Everywhere I read about converting time to a user's timezone says that the best method is to store a date and time in UTC then just add the user's timezone offset to this time.
How can I store a date in UTC time? I use the MySQL DATETIME field.
When adding a new record to MySQL in my PHP code I would use now() to insert into MySQL DATETIME.
Would I need to use something different than now() to store UTC time?
MySQL: UTC_TIMESTAMP()
Returns the current UTC date and time
as a value in 'YYYY-MM-DD HH:MM:SS' or
YYYYMMDDHHMMSS.uuuuuu format,
depending on whether the function is
used in a string or numeric context
PHP: gmdate()
Also PHP date_default_timezone_set() is used in PHP to set the current time zone for the script. You can set it to the client time zone so all the formatting functions return the time in his local time.
In truth though I had a hard time getting this to work and always stumble into some gotcha. Eg. time information returned from MySQL is not formatted as 'UTC' so strtotime transforms it into a local time if you are not careful. I'm curious to hear if someone has a reliable solution for this problem, one that doesn't break when dates traverse media boundaries (HTTP->PHP->MySQL and MySQL->PHP->HTTP), also considering XML and RSS/Atom.
I would suggest inserting the date in UTC time zone. This will save you a lot of headaches in the future with daylight saving problems.
INSERT INTO abc_table (registrationtime) VALUES (UTC_TIMESTAMP())
When I query my data I use the following PHP script:
<?php
while($row = mysql_fetch_array($registration)) {
$dt_obj = new DateTime($row['message_sent_timestamp'] ." UTC");
$dt_obj->setTimezone(new DateTimeZone('Europe/Istanbul'));
echo $formatted_date_long=date_format($dt_obj, 'Y-m-d H:i:s');
}
?>
You can replace the DateTimeZone value with one of the available PHP timezones.
NOW() gives you the time (including the timezone offset) of the system running your database. To get UTC date/time you should use UTC_TIMESTAMP() as described in the MySQL Reference Manual.
https://dba.stackexchange.com/questions/20217/mysql-set-utc-time-as-default-timestamp
Quoting all the answer from above link in case of delete:
To go along with #ypercube's comment that CURRENT_TIMESTAMP is stored as UTC but retrieved as the current timezone, you can affect your server's timezone setting with the --default_time_zone option for retrieval. This allows your retrieval to always be in UTC.
By default, the option is 'SYSTEM' which is how your system time zone is set (which may or may not be UTC!):
mysql> SELECT ##global.time_zone, ##session.time_zone;
+--------------------+---------------------+
| ##global.time_zone | ##session.time_zone |
+--------------------+---------------------+
| SYSTEM | SYSTEM |
+--------------------+---------------------+
1 row in set (0.00 sec)
mysql> SELECT CURRENT_TIMESTAMP();
+---------------------+
| CURRENT_TIMESTAMP() |
+---------------------+
| 2012-09-25 16:28:45 |
+---------------------+
1 row in set (0.00 sec)
You can set this dynamically:
mysql> SET ##session.time_zone='+00:00';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT ##global.time_zone, ##session.time_zone;
+--------------------+---------------------+
| ##global.time_zone | ##session.time_zone |
+--------------------+---------------------+
| SYSTEM | +00:00 |
+--------------------+---------------------+
1 row in set (0.00 sec)
Or permanently in your my.cnf:
[mysqld]
**other variables**
default_time_zone='+00:00'
Restart your server, and you will see the change:
mysql> SELECT ##global.time_zone, ##session.time_zone;
+--------------------+---------------------+
| ##global.time_zone | ##session.time_zone |
+--------------------+---------------------+
| +00:00 | +00:00 |
+--------------------+---------------------+
1 row in set (0.00 sec)
mysql> SELECT CURRENT_TIMESTAMP();
+---------------------+
| CURRENT_TIMESTAMP() |
+---------------------+
| 2012-09-25 20:27:50 |
+---------------------+
1 row in set (0.01 sec)
As #Haluk suggests, you can store the date as a UTC datetime .
I'm complementing his answer for situations when the date you want to insert comes from PHP code, and adding some details about how it works :
$pdo = new PDO('mysql:host=mydbname.mysql.db;dbname=mydbname', 'myusername', 'mypassword');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$insertStmt = $pdo->prepare("insert into test (last_modified)"
." values(:last_modified)");
$insertStmt->bindParam(':last_modified', $lastModified, PDO::PARAM_STR);
$lastModified = gmdate("Y-m-d H:i:s");
$insertStmt->execute();
Actually datetime in PHP doesn't have a timezone associated to it. What is passed to PDO is just a string, in one of the formats recognized by MySQL, representing the date in UTC timezone. For example if the date is 2015-10-21 19:32:33 UTC+2:00, the code above just tells MySQL to insert 2015-10-21 17:32:33. gmtdate("Y-m-d H:i:s") gives you the current date in such a format. In any case, all you need to do is build the string representing the date you want to insert in UTC time.
Then, when you read the date, you have to tell PHP that the timezone of the date you just retrieved is UTC. Use the code in Haluk's answer for this.
Random: UTC_TIMESTAMP(6) for time with 6 digits of microseconds.
MySQL 5.7+
As per (https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html) set the timezone upon connection:
SET TIME_ZONE = 'UTC';
After that all datetime functions should be in UTC.
Refrain from using TIMESTAMP() it is not Y2038 save.
Date and time in MySQL can be stored as DATETIME, TIMESTAMP, and INTEGER (number of seconds since 01/01/1970). What are the benefits and drawbacks of each, particularly when developing under a LAMP stack?
TIMESTAMP is stored in a MySQL proprietary method (though it's basically just a string consisting of year, month, day, hour, minutes and seconds) and additionally, a field of type TIMESTAMP is automatically updated whenever the record is inserted or changed and no explicit field value is given:
mysql> create table timestamp_test(
id integer not null auto_increment primary key,
val varchar(100) not null default '', ts timestamp not null);
Query OK, 0 rows affected (0.00 sec)
mysql> insert into timestamp_test (val) values ('foobar');
Query OK, 1 row affected (0.00 sec)
mysql> select * from timestamp_test;
+----+--------+----------------+
| id | val | ts |
+----+--------+----------------+
| 1 | foobar | 20090122174108 |
+----+--------+----------------+
1 row in set (0.00 sec)
mysql> update timestamp_test set val = 'foo bar' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from timestamp_test;
+----+---------+----------------+
| id | val | ts |
+----+---------+----------------+
| 1 | foo bar | 20090122174123 |
+----+---------+----------------+
1 row in set (0.00 sec)
mysql>
DATETIME is the standard data type for dates and times which works in conjunction with the date and time functions in MySQL. I'd probably use this in practice
Storing dates in INTEGER format is not recommended, as you are opening a real can of worms due to interesting problems like time zones, leap years and the like - at least if you intend to query the database based on specific dates stored in that field.
I would save data using the DATETIME or DATE fields in MySQL. At least, if you are going to store date values up to the year 2038: http://en.wikipedia.org/wiki/Year_2038_problem. If you're on a system that stores integers differently, you may not have this issue.
It is still easy to compare date values or even timestamps.
SELECT * FROM myTable WHERE startDate > '2009-01-01'
SELECT * FROM myTable WHERE UNIX_TIMESTAMP(startDate) > 1232541482
Well I guess the following would help clarify.
Date and time can be stored in a DATETIME field in mysql.
TIMESTAMP is used if you wish to timestamp when a row was created - the field will be automatically filled in on creation.
Using an integer for a Date is slightly overkill since this is essentially what DATETIME does but does all the time consuming conversions for you.
Is there a particular benefit or drawback you are interested in finding out about?
Timestamp in mysql can be very tricky. If not declared carefully you may end up with field that automatically changes its value on every row update (even if you dont update it explicitly).
http://dev.mysql.com/doc/refman/5.0/en/timestamp.html
If you need millisecond fidelity for a timestamp, you need to save it as an Integer. Use caution though, this can complicate things.