Here's a simple version of the table users:
+--------------+-------------------+
| id | timezone |
+--------------+-------------------+
| 1 | 'Europe/Helsinki' |
| 2 | 'Europe/Paris' |
+--------------+-------------------+
I want to know what's the local time for each one of these users (depending on their time zones), so that I can select users for who it's 4pm for example.
I'm using the LAMP stack, but I'd like to do that using MySQL only (not selecting all users and running them in a PHP loop).
Use the CONVERT_TZ for this:
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_convert-tz
SELECT * FROM users WHERE hour(CONVERT_TZ(now(), server_tz, `timezone`))=16
You can change the timezone with set time_zone:
mysql> set time_zone='Europe/Helsinki';
mysql> select now();
2012-09-21 16:15:06
mysql> set time_zone='Europe/Paris';
mysql> select now();
2012-09-21 15:15:40
Using this you can, for example, define a function that returns the current time for the user's timezone:
create function current_time_in_tz(tz varchar(40)) returns datetime
begin
set #old_tz = ##session.time_zone;
set time_zone=tz;
set #now = now();
set time_zone=#old_tz;
return #now;
end
select id, current_time_in_tz(timezone) from users;
Note that DATE, TIME and DATETIME values don't depend on the time zone, so values from columns of these types are not automatically adjusted when querying. TIMESTAMP values are adjusted:
mysql> create temporary table tbl (dt datetime, ts timestamp);
mysql> insert into tbl values (now(),now());
mysql> select * from tbl;
+---------------------+---------------------+
| dt | ts |
+---------------------+---------------------+
| 2012-09-21 15:21:56 | 2012-09-21 15:21:56 |
+---------------------+---------------------+
mysql> set time_zone='Europe/Helsinki';
mysql> select * from tbl;
+---------------------+---------------------+
| dt | ts |
+---------------------+---------------------+
| 2012-09-21 15:21:56 | 2012-09-21 16:21:56 |
+---------------------+---------------------+
If set time_zone fails with this error:
ERROR 1298 (HY000): Unknown or incorrect time zone: 'Europe/Helsinki'
you need to load the time zone info into mysql with a command like this:
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
For more info see http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html
A more generic (not depending on the timezone of the server) solution than Nin's answer would be:
SELECT * FROM users WHERE hour( CONVERT_TZ(UTC_TIMESTAMP(), 'UTC', timezone) )=16
It would be nice if MySQL had a function like NOW_TZ(timezone).
Related
I've a column in a table (varchar) with dates in this format
2013-09-05T10:10:02Z
How do I convert this into datetime format and save it in another column, using an update query?
You can use the STR_TO_DATE function:
UPDATE table1 SET col2 = STR_TO_DATE(col1,'%Y-%m-%dT%TZ')
Example:
mysql> select STR_TO_DATE('2013-09-05T10:10:02Z','%Y-%m-%dT%TZ');
+----------------------------------------------------+
| STR_TO_DATE('2013-09-05T10:10:02Z','%Y-%m-%dT%TZ') |
+----------------------------------------------------+
| 2013-09-05 10:10:02 |
+----------------------------------------------------+
1 row in set (0.00 sec)
You can also use CAST('2013-09-05T10:10:02Z' AS DATETIME) which does not require a format definition as in STR_TO_DATE().
If you want to take care of the timezone just use this query, and use the mysql timezone
mysql> select CONVERT_TZ("2013-09-05T10:10:02Z", "+00:00", ##session.time_zone);
+-------------------------------------------------------------------+
| CONVERT_TZ("2013-09-05T10:10:02Z", "+00:00", ##session.time_zone) |
+-------------------------------------------------------------------+
| 2013-09-05 12:10:02 |
+-------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
or any other timezone
mysql> select CONVERT_TZ("2013-09-05T10:10:02Z", "+00:00", "+03:00");
+--------------------------------------------------------+
| CONVERT_TZ("2013-09-05T10:10:02Z", "+00:00", "+03:00") |
+--------------------------------------------------------+
| 2013-09-05 13:10:02 |
+--------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
I tried using the cast method from above but would get the truncated error as describe in the comments.
You can also use CAST('2013-09-05T10:10:02Z' AS DATETIME) which does not require a format definition as in STR_TO_DATE().
I would consistently get: Error: Truncated incorrect datetime value: '2011-10-02T23:25:42Z'
I fixed it by casting the value to an # variable before using it in my query. Here is an example in a Stored Procedure:
CREATE PROCEDURE `new_procedure`(IN p_date VARCHAR(50), p_text VARCHAR(500))
BEGIN
SET #datestring = CAST(p_date AS DATETIME);
-- used for debugging
SELECT #datestring, p_text;
INSERT INTO testtable(timestamp, text) VALUES(#datestring, p_text);
END
Hi I have following values stored in MySQL table:
--- ------------------------ -------------------
Id | StartDate (VARCHAR (20)) | EndDate(VARCHAR(20))
--- ------------------------ -------------------
1 | 03-04-2017 | 18-04-2017
I am using the following SQL to find if the date is within the StartDate and EndDate:
SELECT
(date_format(str_to_date('03-04-2017','%d-%m-%Y'),'%d-%m-%Y') >= StartDate
AND
date_format(str_to_date('03-04-2017','%d-%m-%Y'),'%d-%m-%Y') <= EndDate) AS
valid
FROM holiday
My issue is it that when I execute the query and provide 03-04-2017 it returns 1 but also returns 1 when I provide 03-05-2017.
Could someone please highlight what is wrong in this query?
Use a query like this:
SELECT *
FROM holiday
WHERE
STR_TO_DATE(StartDate,'%d-%m-%Y')
BETWEEN
str_to_date('03-04-2017','%d-%m-%Y')
AND
str_to_date('03-04-2017','%d-%m-%Y');
sample
mysql> SELECT IF(STR_TO_DATE('11-04-2017','%d-%m-%Y')
-> BETWEEN
-> str_to_date('03-04-2017','%d-%m-%Y')
-> AND
-> str_to_date('10-04-2017','%d-%m-%Y')
->
-> ,'YES','NO') AS ANSWER;
+--------+
| ANSWER |
+--------+
| NO |
+--------+
1 row in set (0,00 sec)
mysql> SELECT IF(STR_TO_DATE('04-04-2017','%d-%m-%Y')
-> BETWEEN
-> str_to_date('03-04-2017','%d-%m-%Y')
-> AND
-> str_to_date('10-04-2017','%d-%m-%Y')
->
-> ,'YES','NO') AS ANSWER;
+--------+
| ANSWER |
+--------+
| YES |
+--------+
1 row in set (0,01 sec)
mysql>
You can use BETWEEN operator to compare the dates, e.g.:
SELECT *
FROM `table`
WHERE '2017-04-03' BETWEEN start_date AND end_date;
Update
If the dates are stored as varchar then you need to convert it to date before comparing, e.g.:
SELECT *
FROM table
WHERE '2017-04-03' BETWEEN STR_TO_DATE(start_date, '%d-%m-%Y') AND STR_TO_DATE(end_date, '%d-%m-%Y');
Here's the SQL Fiddle.
All other answers are good for your question but in my opinion you should convert your database.
It's only sane option.
Using dates in weird VARCHAR format will have big impact in future. Not only it impacts perfomances of your tables right now but you are missing whole MySQL date API ecosystem because of it.
Add temporary columns let's say tmp_start_time DATE
Fill them with dates UPDATE holiday SET tmp_start_time = str_to_date(start_time,'%d-%m-%Y')
Drop old varchar keys in table
Add same keys but as DATE
Update them UPDATE holiday SET start_time = tmp_start_time
From now on you would be able to use BETWEEN as everyone else without str_to_date
I just found your comment
unfortunately I cannot change schema
ask yourself twice: are you sure?
can someone help me with this, my resulting table is showing only zeros for the timestamp. I tried changing the field type to datatime and timestamp but not luck
MYSQL
LOAD DATA LOCAL INFILE 'vals.csv'
INTO TABLE vals
FIELDS TERMINATED BY ","
LINES TERMINATED BY "\n"
IGNORE 1 LINES
(#varTimeSt,NOMINAL,NAME,ID,VAL) SET DATETIME = STR_TO_DATE(#varTimeSt,'%d/%m/%Y %h:%i:%s');
CSV File
DATETIME,NAME,ID,VAL
"25/08/2016 02:00:00",tom,cNum6,12
"25/08/2016 02:00:00",Charles,cNum7,10.58
"25/08/2016 02:00:00",Donal,cNum8,10.18
"25/08/2016 02:00:00",Duncan,cNum7,10.31
Resulting table
DATETIME,NAME,ID,VAL
0000-00-00 00:00:00,tom,cNum6,12
0000-00-00 00:00:00,Charles,cNum7,10.58
0000-00-00 00:00:00,Donal,cNum8,10.18
0000-00-00 00:00:00,Duncan,cNum7,10.31
Your problem is that your dates are not in native mysql DATETIME format (%Y-%m-%d %H:%i:%s), this can be shown as such:
mysql> SELECT CAST('25/08/2016 02:00:00' AS DATETIME);
+-----------------------------------------+
| CAST('25/08/2016 02:00:00' AS DATETIME) |
+-----------------------------------------+
| NULL |
+-----------------------------------------+
1 row in set, 1 warning (0,00 sec)
mysql> SHOW WARNINGS;
+---------+------+-------------------------------------------------+
| Level | Code | Message |
+---------+------+-------------------------------------------------+
| Warning | 1292 | Incorrect datetime value: '25/08/2016 02:00:00' |
+---------+------+-------------------------------------------------+
1 row in set (0,00 sec)
The solution is to get them into MySQL format, this could be done by manipulating your DATETIME column on disk or at source. This may be more difficult than the 'self sufficient' solution I'll outline below.
There exists the string to date (STR_TO_DATE) function to solve this kind of issue once data is inside the database, here is a demonstration with your format. Otherwise see the manual here. (See the DATE_FORMAT section for a table with the codes you can use for different date formats.):
mysql> SELECT CAST(STR_TO_DATE('25/08/2016 02:00:00', '%d/%m/%Y %H:%i:%s') AS DATETIME);
+---------------------------------------------------------------------------+
| CAST(STR_TO_DATE('25/08/2016 02:00:00', '%d/%m/%Y %H:%i:%s') AS DATETIME) |
+---------------------------------------------------------------------------+
| 2016-08-25 02:00:00 |
+---------------------------------------------------------------------------+
1 row in set (0,00 sec)
Personally in this situation I'd load the data into a temporary table that accepted the date fields as a string and then use an INSERT with the STR_TO_DATEfunction to get the data into the final table. A final solution (untested, guideline only) would look like this:
CREATE TEMPORARY TABLE valsLoad (DATETIME TEXT,NAME TEXT,ID TEXT,VAL INT);
LOAD DATA LOCAL INFILE 'vals.csv'
INTO TABLE valsLoad
FIELDS TERMINATED BY ","
LINES TERMINATED BY "\n"
IGNORE 1 LINES
(#varTimeSt,NOMINAL,NAME,ID,VAL) SET DATETIME = STR_TO_DATE(#varTimeSt,'%d/%m/%Y %h:%i:%s');
INSERT INTO vals
SELECT STR_TO_DATE(DATETIME, '%d/%m/%Y %H:%i:%m'), NAME, ID, VAL FROM valsLoad;
DROP TEMPORARY TABLE valsLoad;
Please let me know if you have any questions.
Regards,
James
I am trying to get the date part from a timestamp field.
I used this SQL query:
select timestamp, CAST(timestamp as date) as date from messages
I got the following result:
--------------------------------------------
| timestamp | date |
--------------------------------------------
| 2016-05-15 10:22:54 | 2016-05-16 |
--------------------------------------------
As shown above, the date field produced returns the wrong date 2016-05-16 whereas the original date is 2016-05-15.
How can we resolve this issue?
Thats not a issue !!! Its only set the wrong time_zone. see sample
get current time_zone
SHOW GLOBAL VARIABLES LIKE 'time_zone'; -- systemwide setting
SHOW VARIABLES LIKE 'time_zone'; -- session setting
sample
MariaDB [mysql]> select t, CAST(t as date) FROM groupme LIMIT 1;
+---------------------+-----------------+
| t | CAST(t as date) |
+---------------------+-----------------+
| 2016-05-15 20:22:54 | 2016-05-15 |
+---------------------+-----------------+
1 row in set (0.00 sec)
MariaDB [mysql]> SET time_zone ='-12:00';
Query OK, 0 rows affected (0.00 sec)
MariaDB [mysql]> select t, CAST(t as date) FROM groupme LIMIT 1;
+---------------------+-----------------+
| t | CAST(t as date) |
+---------------------+-----------------+
| 2016-05-14 20:22:54 | 2016-05-14 |
+---------------------+-----------------+
1 row in set (0.00 sec)
MariaDB [mysql]>
Use date not cast because is not casting but a format
select timestamp, date(timestamp) as my_date from messages
I would suggest you to use the DATE_FORMAT function and not the CAST since you are formatting the date like
SELECT `timestamp`, DATE_FORMAT(`timestamp`, '%Y-%m-%d) as my_date from messages
Also note that both CAST and DATE function internally call Item_date_typecast function so there is no such difference between them.
Try this
select timestamp, cast(timestamp as date format 'yyyymmddhhmmss') as date from messages
I've a column in a table (varchar) with dates in this format
2013-09-05T10:10:02Z
How do I convert this into datetime format and save it in another column, using an update query?
You can use the STR_TO_DATE function:
UPDATE table1 SET col2 = STR_TO_DATE(col1,'%Y-%m-%dT%TZ')
Example:
mysql> select STR_TO_DATE('2013-09-05T10:10:02Z','%Y-%m-%dT%TZ');
+----------------------------------------------------+
| STR_TO_DATE('2013-09-05T10:10:02Z','%Y-%m-%dT%TZ') |
+----------------------------------------------------+
| 2013-09-05 10:10:02 |
+----------------------------------------------------+
1 row in set (0.00 sec)
You can also use CAST('2013-09-05T10:10:02Z' AS DATETIME) which does not require a format definition as in STR_TO_DATE().
If you want to take care of the timezone just use this query, and use the mysql timezone
mysql> select CONVERT_TZ("2013-09-05T10:10:02Z", "+00:00", ##session.time_zone);
+-------------------------------------------------------------------+
| CONVERT_TZ("2013-09-05T10:10:02Z", "+00:00", ##session.time_zone) |
+-------------------------------------------------------------------+
| 2013-09-05 12:10:02 |
+-------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
or any other timezone
mysql> select CONVERT_TZ("2013-09-05T10:10:02Z", "+00:00", "+03:00");
+--------------------------------------------------------+
| CONVERT_TZ("2013-09-05T10:10:02Z", "+00:00", "+03:00") |
+--------------------------------------------------------+
| 2013-09-05 13:10:02 |
+--------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
I tried using the cast method from above but would get the truncated error as describe in the comments.
You can also use CAST('2013-09-05T10:10:02Z' AS DATETIME) which does not require a format definition as in STR_TO_DATE().
I would consistently get: Error: Truncated incorrect datetime value: '2011-10-02T23:25:42Z'
I fixed it by casting the value to an # variable before using it in my query. Here is an example in a Stored Procedure:
CREATE PROCEDURE `new_procedure`(IN p_date VARCHAR(50), p_text VARCHAR(500))
BEGIN
SET #datestring = CAST(p_date AS DATETIME);
-- used for debugging
SELECT #datestring, p_text;
INSERT INTO testtable(timestamp, text) VALUES(#datestring, p_text);
END