programing

MySQL datetime 필드 및 여름 시간 - "추가" 시간은 어떻게 참조합니까?

shortcode 2022. 10. 6. 22:06
반응형

MySQL datetime 필드 및 여름 시간 - "추가" 시간은 어떻게 참조합니까?

미국/뉴욕 시간대를 사용하고 있습니다.가을에는 1시간 후퇴합니다.실제로 새벽 2시에 1시간을 '얻는' 셈입니다.전환점에서 다음과 같은 일이 발생합니다.

01:59:00 - 04:00
1분 후에 다음과 같이 됩니다.
01:00:00 - 05:00

그래서 단순히 "1시 30분"이라고 말하면, 첫 번째 1시 30분 롤오버를 말하는 건지 두 번째를 말하는 건지 애매합니다.예약 데이터를 MySQL 데이터베이스에 저장하려고 하는데 시간을 올바르게 저장하는 방법을 결정할 수 없습니다.

문제는 다음과 같습니다.
"2009-11-01 00:30:00"는 2009-11-01 00:30:00 - 04:00로 내부적으로 저장됩니다.
"2009-11-01:30:00"는 2009-11-01 01:30:00 - 05:00로 내부적으로 저장됩니다.

이것은 괜찮고 꽤 예상된 일이다.하지만 01:30:00 - 04:00에 저장하려면 어떻게 해야 하나요? 문서에는 오프셋 지정에 대한 지원이 없기 때문에 오프셋을 지정하려고 하면 무시됩니다.

서머타임을 사용하지 않는 타임존으로 서버를 설정하고 스크립트로 필요한 변환을 하는 것이 유일한 해결책입니다(PHP를 사용하고 있습니다).하지만 그럴 필요는 없을 것 같아요.

제안해 주셔서 감사합니다.

내 목적을 위해 그걸 알아냈어제가 배운 내용을 요약하겠습니다(죄송합니다. 이 메모는 장황하게 쓰여져 있습니다.이 메모는 다른 메모와 마찬가지로 향후 소개에도 도움이 됩니다).

이전 코멘트 중 하나에서 설명한 것과 달리 DATETIME 필드와 TIMESTAMP 필드는 다르게 동작합니다.TIMESTAMP 필드(도큐먼트에 나타나 있듯이)는, 송신한 모든 것을 「YYY-MM-DD hh:mm:ss」형식으로 취득해, 현재의 타임 존에서 UTC 시각으로 변환합니다.데이터를 검색할 때마다 그 반대 현상이 투명하게 발생합니다.DATETIME 필드는 이 변환을 하지 않습니다.그들은 당신이 보낸 모든 것을 가져가서 직접 보관합니다.

DATETIME 필드 유형도 TIMESTAMP 필드 유형도 DST를 준수하는 시간대에 데이터를 정확하게 저장할 수 없습니다."2009-11-01:30:00"를 저장할 경우 필드에서는 원하는 오전 1:30 버전(-04:00 또는 -05:00 버전)을 구분할 수 없습니다.

좋습니다. 그럼 데이터를 DST 이외의 시간대(UTC 등)에 저장해야 합니다.TIMESTAMP 필드가 이 데이터를 정확하게 처리할 수 없는 이유는 시스템이 DST 시간대로 설정되어 있는 경우 TIMESTAMP에 입력한 내용이 다시 출력되지 않을 수 있기 때문입니다.이미 UTC로 변환한 데이터를 전송하더라도 데이터가 로컬 시간대에 있는 것으로 가정하고 UTC로 다시 변환됩니다.TIMESTAMP에 의해 강제된 이 로컬에서 UTC로 돌아가는 왕복은 로컬타임존이 DST를 준수하면 손실됩니다(「2009-11-01:30:00」는 가능한2개의 다른 시각에 매핑되기 때문입니다).

DATTIME을 사용하면 원하는 시간대에 데이터를 저장할 수 있으며, 전송한 데이터를 모두 반환할 수 있습니다(TIMESTAMP 필드가 제공하는 손실된 왕복 변환에 강제로 영향을 주지 않음).따라서 DATETIME 필드를 사용하여 저장하기 전에 시스템 시간대에서 DST 이외의 존으로 변환합니다(UTC가 가장 좋은 옵션이라고 생각합니다).이것에 의해, 변환 로직을 스크립트 언어에 짜넣어, UTC 대응의 「2009-11-01:30:00 - 04:00」또는 「2009-11-01:30:00 - 05:00」를 명시적으로 보존할 수 있습니다.

또 다른 중요한 점은 날짜를 DST TZ에 저장할 경우 MySQL의 날짜/시간 연산 함수가 DST 경계 주변에서 제대로 작동하지 않는다는 것입니다.따라서 UTC에 저장해야 하는 이유가 더욱 커집니다.

한마디로 이렇게 하겠습니다.

데이터베이스에서 데이터를 검색할 때:

정확한 Unix 타임스탬프를 얻으려면 데이터베이스의 데이터를 MySQL 외부에서 UTC로 명시적으로 해석합니다.이를 위해 PHP의 strtotime() 함수 또는 해당 DateTime 클래스를 사용합니다.Convert_ 때문에 MySQL의 CONVERT_TZ() 또는 UNIX_TIMESTamp() 함수를 사용하여 MySQL 내에서 확실하게 실행할 수 없습니다.TZ는 애매성 문제를 일으키는 'YYY-MM-DD hh:mm:ss' 값만 출력합니다.UNIX_TIMESTamp()는 입력이 실제로 데이터가 저장된 시간대가 아닌 시스템 시간대에 있다고 가정합니다.

데이터를 데이터베이스에 저장하는 경우:

날짜를 MySQL 외부에서 원하는 정확한 UTC 시간으로 변환합니다.예를 들어 PHP의 DateTime 클래스에서는 "2009-11-01 1:30:00 EST"와 "2009-11-01 1:30:00 EDT"를 구분하여 지정한 후 UTC로 변환하고 올바른 UTC 시간을 DATETIME 필드에 저장할 수 있습니다.

휴. 여러분의 조언과 도움에 정말 감사드립니다.이게 앞으로 다른 사람의 골칫거리를 덜어주길 바라.

그런데 MySQL 5.0.22 및 5.0.27에서 볼 수 있습니다.

MySQL의 날짜 유형은 UTC 또는 GMT-5와 같은 일정한 오프셋 시간대로 설정되어 있지 않으면 항상 올바르게 저장할 수 없습니다.(MySQL 5.0.45를 사용하고 있습니다)

이는 서머타임이 종료되기 전 시간에는 시간을 저장할 없기 때문입니다.날짜 입력 방법에 관계없이 모든 날짜 함수는 이러한 시간을 전환 후 1시간 이내인 것처럼 처리합니다.

시스템 표준 시간대는America/New_York1257051600 (2009년 11월 1일 일요일 06:00:00 +0100)을 저장해 보겠습니다.

독자적인 INTERVAL 구문을 사용하고 있습니다.

SELECT UNIX_TIMESTAMP('2009-11-01 00:00:00' + INTERVAL 3599 SECOND); # 1257051599
SELECT UNIX_TIMESTAMP('2009-11-01 00:00:00' + INTERVAL 3600 SECOND); # 1257055200

SELECT UNIX_TIMESTAMP('2009-11-01 01:00:00' - INTERVAL 1 SECOND); # 1257051599
SELECT UNIX_TIMESTAMP('2009-11-01 01:00:00' - INTERVAL 0 SECOND); # 1257055200

심지어.FROM_UNIXTIME()정확한 시간이 돌아오지 않습니다.

SELECT UNIX_TIMESTAMP(FROM_UNIXTIME(1257051599)); # 1257051599
SELECT UNIX_TIMESTAMP(FROM_UNIXTIME(1257051600)); # 1257055200

이상하게도 DATETIME은 여전히 DST가 시작되는 "lost" 시간 내에 (문자열 형식으로만!) 시간을 저장하고 반환합니다.2009-03-08 02:59:59단, MySQL 함수에 다음 날짜를 사용하는 것은 위험합니다.

SELECT UNIX_TIMESTAMP('2009-03-08 01:59:59'); # 1236495599
SELECT UNIX_TIMESTAMP('2009-03-08 02:00:00'); # 1236495600
# ...
SELECT UNIX_TIMESTAMP('2009-03-08 02:59:59'); # 1236495600
SELECT UNIX_TIMESTAMP('2009-03-08 03:00:00'); # 1236495600

요점:연중 매번 저장 및 검색해야 하는 경우 몇 가지 바람직하지 않은 옵션을 사용할 수 있습니다.

  1. 시스템 시간대를 GMT + 일정한 오프셋으로 설정합니다.예: UTC
  2. 날짜를 INT로 저장(Aaron이 발견한 것처럼 TIMESTAMP는 신뢰할 수조차 없음)

  3. DATETIME 유형에 일정한 오프셋 시간대가 있다고 가정합니다.예: 에 참가하고 있는 경우America/New_York날짜를 MySQL 외부에서 GMT-5로 변환한 후 DATETIME으로 저장하십시오(필수 사항: Aaron's 답변 참조).MySQL의 날짜/시간 함수를 사용할 때는 매우 주의해야 합니다. 일부에서는 사용자의 값이 시스템 시간대에 속한다고 가정하고 다른 함수(특히 시간 산술 함수)는 "시간대에 구애받지 않습니다"(시간이 UTC인 것처럼 동작할 수 있습니다).

Aaron과 나는 자동 생성 TIMESTAMP 열도 고장났다고 생각합니다.둘다요.2009-11-01 01:30 -0400그리고.2009-11-01 01:30 -0500애매모호하게 저장됩니다.2009-11-01 01:30.

mikawittman의 링크는 다음과 같은 MySQL 제한에 대한 가장 실용적인 솔루션을 제공합니다.연결 시 세션 시간대를 UTC로 설정합니다.

SET SESSION time_zone = '+0:00'

그럼 Unix 타임스탬프만 보내주시면 됩니다.

하지만 01:30:00 - 04:00에 저장하려면 어떻게 해야 하나요?

다음과 같이 UTC로 변환할 수 있습니다.

SELECT CONVERT_TZ('2009-11-29 01:30:00','-04:00','+00:00');


Even better, save the dates as a 타임스탬프 field. That's always stored in UTC, and UTC doesn't know about summer/winter time.

CONVERT_를 사용하여 UTC에서 로컬 시간으로 변환할 수 있습니다.TZ:

SELECT CONVERT_TZ(UTC_TIMESTAMP(),'+00:00','SYSTEM');

여기서 '+00:00'은 UTC, 'from timezone', 'SYSTEM'은 MySQL이 실행되는 OS의 로컬 시간대입니다.

Mysql은 기본적으로 mysql db의 time_zone_name 테이블을 사용하여 이 문제를 해결합니다.CONVERT_ 사용서머타임이 걱정되지 않고 날짜/시간을 업데이트하기 위해 CRUD를 사용하는 동안 TZ.

SELECT
  CONVERT_TZ('2019-04-01 00:00:00','Europe/London','UTC') AS time1,
  CONVERT_TZ('2019-03-01 00:00:00','Europe/London','UTC') AS time2;

이 실타래가 날 소름끼치게 했어TIMESTAMP를 사용하여 열을 짓다On UPDATE CURRENT_TIMESTAMP(즉,recordTimestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP변경된 레코드 및 ETL을 데이터 웨어하우스로 추적합니다.

혹시나 하는 생각이 들까 봐, 이 경우엔TIMESTAMP올바르게 동작하고, 같은 2개의 날짜를 구별하려면 , 다음의 값을 변환합니다.TIMESTAMPunix 타임스탬프:

select TestFact.*, UNIX_TIMESTAMP(recordTimestamp) from TestFact;

id  recordTimestamp         UNIX_TIMESTAMP(recordTimestamp)
1   2012-11-04 01:00:10.0   1352005210
2   2012-11-04 01:00:10.0   1352008810

페이지 방문 횟수 로깅과 그래프 표시(Flot jQuery 플러그인 사용) 작업을 하고 있었습니다.표를 테스트 데이터로 채웠더니 모든 것이 괜찮아 보였는데, 그래프 끝에 x축 라벨에 따라 포인트가 하루 어긋난 것을 알 수 있었습니다.검사 결과, 2015-10-25일째의 뷰 카운트가 데이터베이스에서 2회 취득되어 Flot에 전달되었기 때문에, 이 날짜 이후 매일 오른쪽으로 하루씩 이동했습니다.
잠시 코드의 버그를 찾아본 결과, 이 날짜가 DST가 이루어지는 날이라는 것을 알게 되었습니다.그러다가 SO페이지에 와서...
...하지만 제안된 해결책은 제가 필요로 하는 것에 대한 과잉 살상이었거나 다른 단점이 있었습니다.애매한 타임스탬프를 구분하지 못하는 것은 그다지 걱정하지 않습니다.매일 기록을 세고 표시하기만 하면 됩니다.

먼저 날짜 범위를 검색합니다.

SELECT 
    DATE(MIN(created_timestamp)) AS min_date, 
    DATE(MAX(created_timestamp)) AS max_date 
FROM page_display_log
WHERE item_id = :item_id

포루프에서는 '포루프에서 '포루프'를 으로 '포루프'를 쓰겠습니다.min_date은 로로다 ,이다로 끝납니다max_date1일))60*60*24), 「:」, 「수치」를

for( $day = $min_date_timestamp; $day <= $max_date_timestamp; $day += 60 * 60 * 24 ) {
    $query = "
        SELECT COUNT(*) AS count_per_day
        FROM page_display_log
        WHERE 
            item_id = :item_id AND
            ( 
                created_timestamp BETWEEN 
                '" . date( "Y-m-d 00:00:00", $day ) . "' AND
                '" . date( "Y-m-d 23:59:59", $day ) . "'
            )
    ";
    //execute query and do stuff with the result
}

의 문제에 대한 최종적이고 신속한 해결책은 다음과 같습니다.

$min_date_timestamp += 60 * 60 * 2; // To avoid DST problems
for( $day = $min_date_timestamp; $day <= $max_da.....

그래서 나는 하루의 시작에서 루프를 보는 것이 아니라시간 후에 보는 이다.타임스탬프의 실제 시각에 관계없이 00:00:00 ~23:59:59 사이의 레코드를 데이터베이스에 명시적으로 요구하기 때문에 요일은 그대로이며 올바른 카운트를 취득하고 있습니다.그리고 시간이 한 시간씩 뛰어도, 나는 여전히 올바른 하루를 보내고 있다.

주의: 5년 전의 스레드이며, OPs 질문에 대한 답변이 아닌 것은 알지만, 이 페이지를 접한 저 같은 사람이 제가 설명한 문제에 대한 해결책을 찾는 데 도움이 될 수 있습니다.

언급URL : https://stackoverflow.com/questions/1646171/mysql-datetime-fields-and-daylight-savings-time-how-do-i-reference-the-extra

반응형