이 아마 가장 잘 해결하여, 구문 분석와 MySQL의 기본 형식으로 저장 형식에서 타임 스탬프를 변환하는 저장 기능을 사용하여 내장 된 날짜 시간 수학 표준 시간대 변환을 수행하는 기능
아래 함수는 올바르게 구성된 MySQL datetime 리터럴뿐만 아니라 YYYY-MM-DDTHH:MM:SSZ
과 YYYY-MM-DDTHH:MM:SS+/-HH:MM
의 두 가지 형식을 올바르게 처리하며 수정되지 않은 상태로 전달됩니다.
DELIMITER $$
DROP FUNCTION IF EXISTS `from_iso8601_subset` $$
CREATE FUNCTION `from_iso8601_subset`(in_ts TINYTEXT) RETURNS DATETIME
DETERMINISTIC
NO SQL
BEGIN
-- this function takes an input timestamp value in a suppported subset of iso8601 values, and
-- and converts it to the equivalent MySQL datetime value, expressed in the current session's
-- time zone. Since this is also the timezone that columns in the TIMESTAMP data type expect,
-- this causes the input value to be stored correctly in the native TIMESTAMP format, which is.
-- UTC under the hood.
-- if you are taking the value here and stuffing it into a DATETIME column, you need to have your
-- session @@time_zone set to the same zone in which that column should be stored, or use
-- CONVERT(from_iso('input value'),'UTC','Your Desired Time Zone');
-- unexpected values will be cast as a datetime.
DECLARE offset_sign TINYINT DEFAULT NULL;
DECLARE offset_hours TINYINT DEFAULT NULL;
DECLARE offset_minutes TINYINT DEFAULT NULL;
-- 2014-02-01T23:59:59Z --
IF (in_ts REGEXP '^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}T[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}Z$') THEN
RETURN CONVERT_TZ(REPLACE(REPLACE(in_ts,'T',' '),'Z',''),'UTC',@@time_zone);
-- 2014-09-18T07:00-06:00 -- or +05:00
ELSEIF (in_ts REGEXP '^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}T[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}[+-][[:digit:]]{2}:[[:digit:]]{2}$') THEN
SET offset_sign = IF(SUBSTRING(in_ts FROM 20 FOR 1) = '+', -1, +1); # we need to flip the sign, to "back out" the offset to get a time in UTC
SET offset_hours = CAST(SUBSTRING(in_ts FROM 21 FOR 2) AS SIGNED) * offset_sign;
SET offset_minutes = CAST(SUBSTRING(in_ts FROM 24 FOR 2) AS SIGNED) * offset_sign;
RETURN CONVERT_TZ(DATE_ADD(DATE_ADD(REPLACE(SUBSTRING(in_ts FROM 1 FOR 19),'T',' '), INTERVAL offset_hours HOUR), INTERVAL offset_minutes MINUTE),'UTC',@@time_zone);
-- unexpected format -- let MySQL's built-in functions do the best they can; this will throw warnings
-- if the input is not a yyyy-mm-dd hh:mm:ss datetime literal; alternately this could return NULL.
ELSE
RETURN CAST(in_ts AS DATETIME);
END IF;
END $$
DELIMITER ;
출력 예 :
mysql> SET @@time_zone = 'America/New_York';
Query OK, 0 rows affected (0.08 sec)
mysql> SELECT from_iso8601_subset('2014-06-01T00:00:00+02:00');
+--------------------------------------------------+
| from_iso8601_subset('2014-06-01T00:00:00+02:00') |
+--------------------------------------------------+
| 2014-05-31 18:00:00 |
+--------------------------------------------------+
1 row in set (0.08 sec)
mysql> set @@time_zone = 'UTC';
Query OK, 0 rows affected (0.08 sec)
mysql> SELECT from_iso8601_subset('2014-06-01T00:00:00+02:00');
+--------------------------------------------------+
| from_iso8601_subset('2014-06-01T00:00:00+02:00') |
+--------------------------------------------------+
| 2014-05-31 22:00:00 |
+--------------------------------------------------+
1 row in set (0.08 sec)
우리는 입력 데이터 패턴 중 하나와 일치하는 경우, 그 전달 된 값의 내용도 온전한 될 것이다한다고 가정; 말도 안되는 입력 값을 주면 '+99 : 00'시간대를 사용하는 경우와 같이 말도 안되는 출력이 나오지만 실패하지는 않습니다. 이 함수에는 SQL 주입 취약점이 없습니다.
코드는 더욱 최적화 될 수 있지만 작성된 것처럼이 함수는 중간 정도의 성능을 가진 컴퓨터에서 초당 수천 개의 표현식을 평가할 수있을만큼 효율적입니다.
그건 속임수 였어. 감사! 쿼리에 대괄호가 없습니다.이 쿼리의 작동 방식은 다음과 같습니다. 'ant * from ivocall_calls WHERE 'Vinh Nguyen' 2014-06-01T00 : 00 : 00 + 02 : 00 ') 및 unix_timestamp ('2014-06-30T00 : 00 : 00 + 02 : 00 ')' – denn
흥미로운 대답이지만 매우 잘못되었습니다. unix_timestamp 함수는 기껏해야 인수의 표준 시간대 정보를 무시하고 세션의 시간대를 가정합니다. 그 쿼리를 실행 한 다음'SHOW WARNINGS;'를 실행하십시오. –
@ 마이클 : 저는 새로운 것을 배워서 항상 행복합니다. 모든 항목이 같은 시간대에있는 경우 내 솔루션이 여전히 OP에 적용될 수 있습니다. 그러나 나는 그것이 권장할만한 해결책이 아니라는 것을 인정해야합니다. –