web-dev-qa-db-ja.com

オフセット未処理およびオフセット対応の日時を減算できません

PostgreSQLにタイムゾーン対応のtimestamptzフィールドがあります。テーブルからデータを取得するとき、その時点の時間を取得できるように、今すぐ時間を減算したいです。

私が抱えている問題は、datetime.datetime.now()datetime.datetime.utcnow()の両方がタイムゾーンを認識しないタイムスタンプを返すようであるため、このエラーが発生することです:

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

これを回避する方法はありますか(できればサードパーティのモジュールを使用しないで)。

編集:提案に感謝しますが、タイムゾーンを調整しようとするとエラーが発生するようです。したがって、PGでタイムゾーンを認識しないタイムスタンプを使用し、常に次のものを使用して挿入します。

NOW() AT TIME ZONE 'UTC'

そうすれば、私のタイムスタンプはすべてデフォルトでUTCになります(これを行うのはもっと面倒ですが)。

234
Ian

タイムゾーン認識を削除しようとしましたか?

from http://pytz.sourceforge.net/

naive = dt.replace(tzinfo=None)

タイムゾーンの変換も追加する必要があります。

編集:この答えの年齢に注意してください。 Python 3の回答は次のとおりです。

255
phillc

正しい解決策は、addタイムゾーン情報です。たとえば、Python 3の認識された日時オブジェクトとして現在の時刻を取得します。

from datetime import datetime, timezone

now = datetime.now(timezone.utc)

古いPythonバージョンでは、utc tzinfoオブジェクトを自分で定義できます(datetime docsの例):

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)
142
jfs

この種のデータベース相互作用を抽象化するためのインターフェイスとしてDjangoを使用する人がいることは知っています。 Djangoは、これに使用できるユーティリティを提供します。

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

このタイプのインターフェイスを使用しているだけでも、基本的なDjango設定インフラストラクチャを設定する必要があります(設定では、USE_TZ=Trueを含めて日時を取得する必要があります)。

これだけでは、おそらくDjangoをインターフェイスとして使用するように動機づけるのに十分ではありませんが、他にも多くの特典があります。一方、Djangoアプリをマングルしていたためにここでつまずいた場合は(おそらく私がしたように)、おそらくこれが役立ちます...

49
sage

これは非常にシンプルで明確なソリューションです
2行のコード

# 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

同じ時刻情報で日時変数を管理する必要があります

14
ePi272314

Psycopg2モジュールには独自のタイムゾーン定義があるため、最終的にutcnowのラッパーを作成しました。

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

postgreSQL timestamptzと比較するために現在の時刻が必要なときはいつでもpg_utcnowを使用するだけです

5
erjiang

私も同じ問題に直面しました。それから私は多くの検索の後に解決策を見つけました。

問題は、モデルまたはフォームからdatetimeオブジェクトを取得するときはオフセット対応であり、システムで時刻を取得する場合はオフセットナイーブであるということでした。

だから私はtimezone.now()を使用して現在の時間を取得し、Django.utils import timezoneでタイムゾーンをインポートし、SE_TZ = Trueプロジェクト設定ファイル。

4
Ashok Joshi

私は非常にシンプルなソリューションを思い付きました:

import datetime

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

タイムゾーン対応およびタイムゾーン未処理の日時値の両方で機能します。また、追加のライブラリやデータベースの回避策は不要です。

2
John L. Stanley

PostgreSQL自体で年齢の計算を処理できます。何かのようなもの

select *, age(timeStampField) as timeStampAge from myTable
1
Nic Gibson

timezone.make_aware(datetime.datetime.now())がDjangoで役立つことがわかりました(1.9.1を使用しています)。残念ながら、単にdatetimeオブジェクトをオフセット対応にしてからtimetz()にすることはできません。 datetimeを作成し、それに基づいて比較する必要があります。

1
Joseph Coco

私はこれが古いことを知っていますが、誰かがそれを便利だと思った場合に備えて、私のソリューションを追加すると思いました。

ローカルの単純な日付時刻とタイムサーバーからの認識された日付時刻を比較したかったのです。基本的には、認識された日時オブジェクトを使用して、新しい単純な日時オブジェクトを作成しました。それはちょっとしたハックで、見た目はきれいではありませんが、仕事は完了です。

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 :-(')
0
I_do_python