Rails 및 Postgre에서 시간대를 완전히 무시하는 경우SQL
저는 Rails and Postgres에서 날짜와 시간을 처리하고 있으며 이 문제에 직면해 있습니다.
데이터베이스는 UTC에 있습니다.
사용자는 레일즈 앱에서 선택한 시간대를 설정하지만, 시간 비교를 위해 사용자에게 현지 시간을 제공할 때만 사용됩니다.
사용자는 예를 들어 2012년 3월 17일 오후 7시에 시간을 저장합니다.표준 시간대 변환이나 표준 시간대가 저장되지 않았으면 합니다.저는 단지 그 날짜와 시간을 절약하기를 원합니다.이렇게 하면 사용자가 표준 시간대를 변경하더라도 2012년 3월 17일 오후 7시로 표시됩니다.
사용자가 지정한 시간대를 사용하여 사용자 현지 시간대의 현재 시간을 '이전' 또는 '이후'로 기록합니다.
현재 '타임존이 없는 타임스탬프'를 사용하고 있는데, 기록을 검색하면 레일즈(?)가 앱에서 타임존으로 변환해주는데, 이는 원하지 않습니다.
Appointment.first.time
=> Fri, 02 Mar 2012 19:00:00 UTC +00:00
데이터베이스의 기록이 UTC로 나오는 것 같기 때문에, 제 해킹은 현재 시간을 가지고 'Date.strptime(str, %m/%d/%)으로 시간대를 제거하는 것입니다.Y")"를 선택한 후 다음을 사용하여 쿼리를 수행합니다.
.where("time >= ?", date_start)
주변의 모든 시간대를 그냥 무시할 수 있는 더 쉬운 방법이 있을 것으로 보입니다.아이디어 있어요?
Postgres에는 두 가지 다른 타임스탬프 데이터 유형이 있습니다.
timestamp with time zone짧은 이름:timestamp without time zone짧은 이름:
timestamptz문자 그대로 날짜/시간 계열에서 선호하는 유형입니다.정말 그랬어요.typispreferred에서 설정되며, 관련될 수 있습니다.
내부 스토리지 및 에포크
내부적으로 타임스탬프는 디스크와 RAM의 스토리지 8바이트를 차지합니다.Postgres epoch, 2000-01-01 00:00 UTC의 마이크로초 수를 나타내는 정수 값입니다.
Postgres는 또한 UNIX epoch 1970-01-01 00:00 UTC에서 일반적으로 사용되는 UNIX 시간 계산 초에 대한 기본 지식을 가지고 있으며 함수 또는 에서 이를 사용합니다.
타임스탬프와 간격의 h/m/s 필드는 다음과 같이 저장됩니다.int64 값의 단위는 마이크로초입니다. (옛날에 그것들은두 배 값(초 단위).
그리고:
Unix 및 Postgres 계산에서 0일의 줄리안 날짜 등가 */#207 UNIX_EPOCH_JDATE 2440588 /* == date2j(1970, 1, 1) */#2021 POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000,1,1) */
마이크로초 해상도는 최대 6자리(초)로 변환됩니다.
timestamp
시간대가 명시적으로 제공되지 않습니다.Postgres는 실수로 입력 리터럴에 추가된 시간대 한정자를 무시합니다!
시간은 표시를 위해 이동되지 않습니다.모든 것이 같은 시간대에 발생하기 때문에 이것은 괜찮습니다.다른 시간대의 경우 의미는 변경되지만 값과 표시는 동일하게 유지됩니다.
timestamptz
처리 방법이 미묘하게 다릅니다.설명서를 여기에 인용합니다.
위해서
timestamp with time zone내부에 저장된 값은 항상 UTC(Universal Coordinated Time...)입니다.
굵은 글씨로 강조해주세요.시간대 자체는 저장되지 않습니다.이는 해당 UTC 타임스탬프를 계산하는 데 사용되는 입력 수정자이며, 표시할 로컬 시간을 계산하는 데 사용되는 출력 장식자와 시간대 오프셋이 추가됩니다.다음에 대한 오프셋을 추가하지 않는 경우timestamptz입력 시 세션의 현재 시간대 설정이 가정됩니다.모든 계산은 UTC 타임스탬프 값으로 수행됩니다.할 둘이상시처하경는우야리해를을 합니다.timestamptz즉, 추정된 시간대에 대해 의심이나 오해가 있을 수 있는 경우에는 다음과 같이 합니다.timestamptz대부분의 사용 사례에 적용됩니다.
psql 또는 pgAdmin과 같은 클라이언트 또는 libpq를 통해 통신하는 모든 애플리케이션(예: Ruby와 pgem)은 현재 시간대 또는 요청된 시간대에 따라 타임스탬프와 오프셋을 제공합니다(아래 참조).표시 형식만 다를 뿐 항상 동일한 시점입니다.또는 설명서에 나와 있는 것처럼:
모든 시간대 인식 날짜 및 시간은 UTC에 내부적으로 저장됩니다.클라이언트에 표시되기 전에 구성 매개 변수로 지정된 영역의 로컬 시간으로 변환됩니다.
psql의 예:
db=# SELECT timestamptz '2012-03-05 20:00+03';
timestamptz
------------------------
2012-03-05 18:00:00+01
이게 어찌된 일이냐?
임의의대시간오을선택습다니했셋프▁an다▁zone▁chose니▁i▁time▁arbitrary▁offset임습선을 선택했습니다.+3입력 리터럴에 대해.은 Postgres의 UTC 타임스탬프를 하는 많은 중 입니다.2012-03-05 17:00:00쿼리 결과는 내 테스트에서 오프셋이 있는 현재 시간대 설정 비엔나/오스트리아에 대해 표시됩니다.+1겨울 동안 그리고+2여름 시간 동안("일광 절약 시간", DST).그렇게2012-03-05 18:00:00+01DST는 나중에야 시작되기 때문입니다.
Postgres는 입력 리터럴을 즉시 잊어버립니다.데이터 유형의 값만 기억합니다.십진법처럼 말입니다. numeric '003.4'또는numeric '+3.4'둘 다 정확하게 동일한 내부 값을 생성합니다.
AT TIME ZONE
현재 누락된 것은 특정 시간대에 따라 타임스탬프 리터럴을 해석하거나 표현하는 도구입니다.거기서 구조가 시작됩니다.두 가지 사용 사례가 있습니다. timestamptz는 로변됩니다로 됩니다.timestamp그리고 역도 성립.
UTC timestamptz 2012-03-05 17:00:00+0:
SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC'
이 값은 다음과 같습니다.
SELECT timestamptz '2012-03-05 17:00:00 UTC'
EST와 timestamp주:)
SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC' AT TIME ZONE 'EST'
맞요.AT TIME ZONE 'UTC' 두 번. 첫 번째는 해석합니다.timestamp as UTC 타임스탬프timestamptz두 번째는 다음을 변환합니다.timestamptz에▁timestamp주어진 시간대 'EST'에서 - 이 시점의 시간대 EST에서 벽시계가 표시하는 내용.
예
SELECT ts AT TIME ZONE 'UTC'
FROM (
VALUES
(1, timestamptz '2012-03-05 17:00:00+0')
, (2, timestamptz '2012-03-05 18:00:00+1')
, (3, timestamptz '2012-03-05 17:00:00 UTC')
, (4, timestamp '2012-03-05 11:00:00' AT TIME ZONE '+6')
, (5, timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC')
, (6, timestamp '2012-03-05 07:00:00' AT TIME ZONE 'US/Hawaii') -- ①
, (7, timestamptz '2012-03-05 07:00:00 US/Hawaii') -- ①
, (8, timestamp '2012-03-05 07:00:00' AT TIME ZONE 'HST') -- ①
, (9, timestamp '2012-03-05 18:00:00+1') -- ② loaded footgun!
) t(id, ts);
동일한 UTC 타임스탬프를 포함하는 타임스탬프 z 열이 있는 동일한 행 8개(또는 9개)를 반환합니다.2012-03-05 17:00:009번째 줄은 제 시간대에서 작동하지만 사악한 함정입니다.아래를 참조하십시오.
하와이 시간의 시간대 이름과 시간대 약어가 있는 6 - 8행은 DST(일광 절약 시간)의 영향을 받으며, 현재는 아니지만 다를 수 있습니다.시간대 이름은 다음과 같습니다.'US/Hawaii'자동으로 , DST 규칙및과자인반면로식는동으다, 있다습니약같가어은음과와 같은 약어도 됩니다.HST고정 오프셋에 대한 덤 코드일 뿐입니다.여름/표준 시간에 대해 다른 약어를 추가해야 할 수도 있습니다.이름은 지정된 시간대의 타임스탬프를 올바르게 해석합니다.약어는 저렴하지만 지정된 타임스탬프에 맞는 약어여야 합니다.
일광 절약 시간제는 인류가 생각해낸 가장 밝은 아이디어 중 하나가 아닙니다.
장전된 풋건으로 표시된 9열은 저에게 효과가 있지만, 우연일 뿐입니다.만약 당신이 명시적으로 리터럴을 던지면.timestamp [without time zone]시간대 오프셋은 무시됩니다!맨 타임스탬프만 사용됩니다.그런 다음 값이 자동으로 강제 적용됩니다.timestamptz열 유형과 일치하는 예제입니다.에서는, 이단의경우계,우,timezone인 것으로 합니다.+1내 경우(유럽/빈).그러나 귀하의 경우에는 그렇지 않을 수 있습니다. 이는 다른 값을 초래할 것입니다.간단히 말해서 캐스팅 안 함timestamptz에 대한 리터럴.timestamp또는 표준 시간대 오프셋을 잃게 됩니다.
당신의 질문들
사용자는 예를 들어 2012년 3월 17일 오후 7시에 시간을 저장합니다.표준 시간대 변환이나 표준 시간대가 저장되지 않았으면 합니다.
표준 시간대 자체는 저장되지 않습니다.위의 방법 중 하나를 사용하여 UTC 타임스탬프를 입력합니다.
사용자가 지정한 시간대를 사용하여 사용자 현지 시간대의 현재 시간을 '이전' 또는 '이후'로 기록합니다.
서로 다른 시간대에 있는 모든 클라이언트에 대해 하나의 쿼리를 사용할 수 있습니다.
절대 전역 시간:
SELECT * FROM tbl WHERE time_col > (now() AT TIME ZONE 'UTC')::time
로컬 시계에 따른 시간:
SELECT * FROM tbl WHERE time_col > now()::time
아직 배경 정보에 싫증나지 않으셨나요?설명서에 더 있습니다.
기본적으로 UTC에서 거래하려는 경우:
config/application.rb 추가: 메시지:
config.time_zone = 'UTC'
사용자 에는 사용자 시간대 이름은 " " " 입니다.current_user.timezone말할 수 있습니다.
post.created_at.in_time_zone(current_user.timezone)
current_user.timezone. 유한시이합니야다어이름간대효합다니가 됩니다. 그렇지 않으면ArgumentError: Invalid Timezone전체 목록을 봅니다.
어윈의 답변에 문제의 해결책이 포함되어 있는지는 모르겠지만(아직도 유용한 정보가 많이 포함되어 있습니다), 하지만 저는 한 가지가 있습니다.
더 짧은 솔루션:
(적어도 읽기에는 더 짧음)
.where("created_at > ?", (YOUR_DATE_IN_THE_TIMEZONE).iso8601)
왜 이렇게 엉망이 되는 거지?
다음과 같은 것을 구현하려고 할 때.where("created_at > ?", YOUR_DATE_IN_THE_TIMEZONE)Rails가 개입하여 시간을 서버 시간으로 변환합니다(대부분 UTC). 날짜를 타임스탬프로 변환합니다(시간대 형식이 없는 타임스탬프).그래서 함께 춤을 추는 사람들이in_time_zone그리고 주변은 무의미합니다.
iso8601이 작동하는 이유
에 전화할 때.iso8601당신의 날짜는 Rails가 "브레이크"할 수 없는 문자열로 변환되어 그대로 Postgres에게 전달되어야 합니다.
투표하는 것을 잊지 마세요!
Angular/Typescript/Node API/Postgre에 유사한 퍼즐과 타임스탬프 정확도가 있었습니다.SQL 환경, 여기에 완전한 해답과 솔루션이 있습니다.
언급URL : https://stackoverflow.com/questions/9571392/ignoring-time-zones-altogether-in-rails-and-postgresql
'programing' 카테고리의 다른 글
| Eclipse의 "..." 오류 메시지가 포함된 리포지토리를 찾을 수 없음"에 대해 어떻게 해야 합니까? (0) | 2023.05.14 |
|---|---|
| Swift 클래스의 정적 vs 클래스 함수/변수? (0) | 2023.05.14 |
| Excel의 열에 있는 모든 셀에 동일한 텍스트 추가 (0) | 2023.05.14 |
| 여러 작업에 비동기/대기 사용 (0) | 2023.05.14 |
| Xcode 중복/삭제 라인 (0) | 2023.05.14 |