我在PostgreSQL中有一个时区感知timestamptz字段。当我从表中提取数据时,我想减去现在的时间,这样我就可以得到它的年龄。

我遇到的问题是datetime.datetime.now()和datetime.datetime.utcnow()似乎都返回不知道时区的时间戳,这导致我得到这个错误:

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

是否有办法避免这种情况(最好不使用第三方模块)。

编辑:谢谢你的建议,但试图调整时区似乎给我错误。所以我将在PG中使用不考虑时区的时间戳,并且总是插入using:

NOW() AT TIME ZONE 'UTC'

这样,默认情况下我的所有时间戳都是UTC(尽管这样做更烦人)。


当前回答

我知道这是旧的,但我只是想加上我的解决方案,以防有人发现它有用。

我想比较本地天真datetime和时间服务器上的感知datetime。我基本上使用感知datetime对象创建了一个新的朴素datetime对象。这是一个有点hack,看起来不太漂亮,但可以完成工作。

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

其他回答

标题中对这个问题最直接的回答似乎缺失了:

naive_date.replace(tzinfo=aware_date.tzinfo) - aware_date

正确的解决方案是添加时区信息,例如,在Python 3中获取当前时间作为感知datetime对象:

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)

我知道这是旧的,但我只是想加上我的解决方案,以防有人发现它有用。

我想比较本地天真datetime和时间服务器上的感知datetime。我基本上使用感知datetime对象创建了一个新的朴素datetime对象。这是一个有点hack,看起来不太漂亮,但可以完成工作。

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

您是否尝试删除时区识别?

从http://pytz.sourceforge.net/

naive = dt.replace(tzinfo=None)

可能还得加上时区转换。

编辑:请注意这个答案的年龄。下面是一个涉及添加时区信息而不是在python3中删除它的答案。https://stackoverflow.com/a/25662061/93380

有什么紧迫的原因,为什么你不能处理年龄计算PostgreSQL本身?类似的

select *, age(timeStampField) as timeStampAge from myTable