1

나는 변경할 수없는 MySQL 데이터베이스가 있는데, 여기서 나는 날짜를 읽습니다. 문제는 날짜를 저장하는 varchar 열이 있다는 것입니다. 날짜는 예를 들어 원자 시간 형식으로 저장됩니다. 2014-06-01T00:00:00+02:00.STR_TO_DATE 및 ISO8601 Atomtime 형식

STR_TO_DATE 함수에서 형식을 지정하는 방법을 알 수 없습니다. 나는 STR_TO_DATE(Endtime, '%Y-%m-%dT%H:%i:%s+02:00')을 시도했지만 작동하지 않습니다.

아무에게도 해결책이 있습니까? 사전에

SELECT *, COUNT(*) as antal 
FROM ivocall_calls 
WHERE Agentname LIKE 'Vinh Nguyen' 
    AND Status1 = 'SALG' 
    AND STR_TO_DATE(Endtime, '%Y-%m-%dT%H:%i:%s+02:00') 
     BETWEEN STR_TO_DATE('2014-06-01T00:00:00+02:00', '%Y-%m-%dT%H:%i:%s+02:00') 
      AND STR_TO_DATE('2014-06-30T00:00:00+02:00', '%Y-%m-%dT%H:%i:%s+02:00') 

감사 :

나는 (제대로 작동하지 않습니다) 다음 쿼리를 실행하려합니다. 대신

답변

2

이 아마 가장 잘 해결하여, 구문 분석와 MySQL의 기본 형식으로 저장 형식에서 타임 스탬프를 변환하는 저장 기능을 사용하여 내장 된 날짜 시간 수학 표준 시간대 변환을 수행하는 기능

아래 함수는 올바르게 구성된 MySQL datetime 리터럴뿐만 아니라 YYYY-MM-DDTHH:MM:SSZYYYY-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 주입 취약점이 없습니다.

코드는 더욱 최적화 될 수 있지만 작성된 것처럼이 함수는 중간 정도의 성능을 가진 컴퓨터에서 초당 수천 개의 표현식을 평가할 수있을만큼 효율적입니다.

0

사용 UNIX_TIMESTAMP() :

SELECT something, COUNT() as antal FROM ivocall_calls 
WHERE Agentname LIKE 'Vinh Nguyen' 
AND Status1 = 'SALG' 
AND unix_timestamp(Endtime) BETWEEN 
    unix_timestamp('2014-06-01T00:00:00+02:00' and unix_timestamp('2014-06-30T00:00:00+02:00'); 
+0

그건 속임수 였어. 감사! 쿼리에 대괄호가 없습니다.이 쿼리의 작동 방식은 다음과 같습니다. 'ant * from ivocall_calls WHERE 'Vinh Nguyen' 2014-06-01T00 : 00 : 00 + 02 : 00 ') 및 unix_timestamp ('2014-06-30T00 : 00 : 00 + 02 : 00 ')' – denn

+0

흥미로운 대답이지만 매우 잘못되었습니다. unix_timestamp 함수는 기껏해야 인수의 표준 시간대 정보를 무시하고 세션의 시간대를 가정합니다. 그 쿼리를 실행 한 다음'SHOW WARNINGS;'를 실행하십시오. –

+1

@ 마이클 : 저는 새로운 것을 배워서 항상 행복합니다. 모든 항목이 같은 시간대에있는 경우 내 솔루션이 여전히 OP에 적용될 수 있습니다. 그러나 나는 그것이 권장할만한 해결책이 아니라는 것을 인정해야합니다. –