오프셋 순진 및 오프셋 인식 날짜 시간을 뺄 수 없습니다


305

timestamptzPostgreSQL에 시간대 인식 필드가 있습니다. 테이블에서 데이터를 가져 오면 지금 시간을 빼서 나이를 얻을 수 있습니다.

제가하는 데 문제는 모두이다 datetime.datetime.now()그리고 datetime.datetime.utcnow()나 결과이 오류가 발생 시간대 인식 타임 스탬프를 반환하는 것 :

TypeError: can't subtract offset-naive and offset-aware datetimes 

이것을 피할 수있는 방법이 있습니까 (타사 모듈을 사용하지 않는 것이 좋습니다).

편집 : 제안에 감사하지만 시간대를 조정하려고하면 오류가 발생하는 것 같습니다. 따라서 PG에서 시간대를 인식하지 못하는 시간대를 사용하고 항상 다음을 사용하여 삽입합니다.

NOW() AT TIME ZONE 'UTC'

그렇게하면 모든 타임 스탬프가 기본적으로 UTC입니다 (더 짜증나더라도).

답변:


316

시간대 인식을 제거하려고 했습니까?

에서 http://pytz.sourceforge.net/

naive = dt.replace(tzinfo=None)

시간대 변환을 추가해야 할 수도 있습니다.

편집 :이 답변의 나이를 알고하십시오. Python 3 답변은 다음과 같습니다.


32
이것이 유일한 방법 인 것 같습니다. 파이썬이 타임 스탬프를 제대로 사용하기 위해 써드 파티 모듈을 필요로하는 시간대에 대한 엉뚱한 지원을 받았다고 꽤 불쾌한 것 같습니다.
Ian

33
(기록을
위해서만

7
순진한 datetime 객체는 본질적으로 모호하므로 피해야합니다. 대신 tzinfo를 추가하는
jfs

1
@Kylotan : UTC는이 컨텍스트에서 시간대입니다 (tzinfo 클래스로 표시). datetime.timezone.utc또는을 보십시오 pytz.utc. 예를 들어, 1970-01-01 00:00:00애매 모호하므로 명확성을 기하기 위해 시간대를 추가해야합니다 1970-01-01 00:00:00 UTC. 새 정보 를 추가 해야합니다 . 타임 스탬프 자체는 모호합니다.
jfs

1
@ JFSebastian : 문제는 utcnow시간대가없는 순진한 객체 또는 타임 스탬프를 반환해서는 안된다는 것입니다. 문서에서 "인식 객체는 해석에 개방되지 않은 특정 시점을 나타내는 데 사용됩니다." UTC 기준 언제든지 정의에 따라이 기준을 충족합니다.
Kylotan

213

올바른 해결책은 시간대 정보 를 추가 하는 것입니다. 예를 들어 Python 3에서 현재 시간을 인식 가능한 datetime 객체로 가져옵니다.

from datetime import datetime, timezone

now = datetime.now(timezone.utc)

이전 Python 버전에서는 utctzinfo 객체를 직접 정의 할 수 있습니다 (datetime 문서의 예).

from datetime import tzinfo, timedelta, datetime

ZERO = timedelta(0)

class UTC(tzinfo):
  def utcoffset(self, dt):
    return ZERO
  def tzname(self, dt):
    return "UTC"
  def dst(self, dt):
    return ZERO

utc = UTC()

그때:

now = datetime.now(utc)

10
허용되는 답변이 IMHO를지지하므로 tz를 제거하는 것보다 낫습니다.
Shautieh

3
다음은 파이썬 시간대 목록입니다 : stackoverflow.com/questions/13866926/…
comfytoday

61

일부 사람들은 이러한 유형의 데이터베이스 상호 작용을 추상화하기 위해 Django를 인터페이스로 사용합니다. Django는이를 위해 사용할 수있는 유틸리티를 제공합니다 :

from django.utils import timezone
now_aware = timezone.now()

이 유형의 인터페이스 만 사용하더라도 기본 장고 설정 인프라를 설정해야합니다 (설정에서 USE_TZ=True날짜 시간을 알기 위해 포함해야 함 ).

그 자체로는 아마도 장고를 인터페이스로 사용하도록 동기를 부여 할 정도로 가까운 곳은 아니지만 다른 많은 특전이 있습니다. 반면에, 내가했던 것처럼 장고 앱을 조작했기 때문에 여기에서 넘어 졌다면 아마도 도움이 될 것입니다 ...


1
당신은 USE_TZ=True여기에 날짜 시간을 알기 위해 필요 합니다.
jfs

2
예-JFSebastian이 설명하는 것처럼 settings.py를 설정해야한다고 언급하는 것을 잊었습니다.
Sage

또한 + timedelta(hours=5, minutes=30)IST
ABcDexter

25

이것은 매우 간단하고 명확한 솔루션입니다.
두 줄의 코드

# First we obtain de timezone info o some datatime variable    

tz_info = your_timezone_aware_variable.tzinfo

# Now we can subtract two variables using the same time zone info
# For instance
# Lets obtain the Now() datetime but for the tz_info we got before

diff = datetime.datetime.now(tz_info)-your_timezone_aware_variable

결론 : 동일한 시간 정보로 날짜 시간 변수를 관리해야합니다 .


맞지 않습니까? 내가 작성한 코드는 테스트되었으며 장고 프로젝트에서 사용하고 있습니다. 훨씬 명확하고 간단합니다
ePi272314

"올바르지 않은"은 답의 마지막 문장을 말합니다 : "... UTC가 아닌 ... UTT를 추가해야합니다" -UTC 시간대가 작동하므로 명령문이 올바르지 않습니다.
jfs

분명히 말하면 : diff = datetime.now(timezone.utc) - your_timezone_aware_variable작품 (그리고 (a - b)위 의 공식 은 아닌 (a - b)경우에도 작동 할 수 있는 설명 a.tzinfo입니다 b.tzinfo).
jfs

6

psycopg2 모듈에는 자체 시간대 정의가 있으므로 utcnow 주위에 자체 래퍼를 작성했습니다.

def pg_utcnow():
    import psycopg2
    return datetime.utcnow().replace(
        tzinfo=psycopg2.tz.FixedOffsetTimezone(offset=0, name=None))

pg_utcnowPostgreSQL과 비교하기 위해 현재 시간이 필요할 때마다 사용하십시오.timestamptz


예를 들어 0 utc 오프셋을 반환하는 tzinfo 객체는 수행 합니다.
jfs

6

나는 또한 같은 문제에 직면했다. 그런 다음 많은 검색 후 해결책을 찾았습니다.

문제는 모델이나 양식에서 datetime 객체를 가져올 때 오프셋을 인식 하고 시스템별로 시간을 가져 오면 순진 하다는 것입니다 .

그래서 내가 한 것은 timezone.now () 사용하여 현재 시간 을 얻었고 django.utils import timezone에서 시간대를 가져 와서 프로젝트 설정 파일에 USE_TZ = True 를 넣는 것 입니다.


2

나는 매우 간단한 해결책을 생각해 냈습니다.

import datetime

def calcEpochSec(dt):
    epochZero = datetime.datetime(1970,1,1,tzinfo = dt.tzinfo)
    return (dt - epochZero).total_seconds()

표준 시간대 인식 및 표준 시간대 미정 날짜 시간 값과 함께 작동합니다. 추가 라이브러리 나 데이터베이스 해결 방법이 필요하지 않습니다.


1

timezone.make_aware(datetime.datetime.now())장고에서 도움이되는 것을 발견 했습니다 (1.9.1에 있습니다). 불행히도 단순히 datetime객체를 오프셋 인식 할 수는 없습니다 timetz(). 이를 datetime기반으로 비교를해야합니다.


1

PostgreSQL 자체에서 연령 계산을 처리 할 수없는 중요한 이유가 있습니까? 같은 것

select *, age(timeStampField) as timeStampAge from myTable

2
그렇습니다 .. 그러나 나는 postgre에서 모든 계산을하지 않기를 원하기 때문에 주로 묻습니다.
Ian

0

나는 이것이 오래된 것을 알고 있지만 누군가가 유용하다고 생각하는 경우에 대비하여 솔루션을 추가 할 것이라고 생각했습니다.

로컬 순진 날짜 시간을 시간 서버의 인식 날짜 시간과 비교하고 싶었습니다. 나는 기본적으로 인식하는 datetime 객체를 사용하여 새로운 순진 datetime 객체를 만들었습니다. 그것은 약간의 해킹이며 매우 예쁘지 않지만 작업을 완료합니다.

import ntplib
import datetime
from datetime import timezone

def utc_to_local(utc_dt):
    return utc_dt.replace(tzinfo=timezone.utc).astimezone(tz=None)    

try:
    ntpt = ntplib.NTPClient()
    response = ntpt.request('pool.ntp.org')
    date = utc_to_local(datetime.datetime.utcfromtimestamp(response.tx_time))
    sysdate = datetime.datetime.now()

퍼지가 온다 ...

    temp_date = datetime.datetime(int(str(date)[:4]),int(str(date)[5:7]),int(str(date)[8:10]),int(str(date)[11:13]),int(str(date)[14:16]),int(str(date)[17:19]))
    dt_delta = temp_date-sysdate
except Exception:
    print('Something went wrong :-(')

참고로, utc_to_local()내 대답 에서 현지 시간을 인식 가능한 datetime 객체 로 반환 합니다 (Python 3.3 + 코드 임)
jfs

코드가 무엇을하려고하는지 명확하지 않습니다. 로 바꿀 수 있습니다 delta = response.tx_time - time.time().
jfs
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.