不能减去无偏移量和偏移量感知的日期时间

我在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(尽管这样做更烦人)。

371769 次浏览

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

http://pytz.sourceforge.net/

naive = dt.replace(tzinfo=None)

可能还得加上时区转换。

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

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

select *, age(timeStampField) as timeStampAge from myTable

psycopg2模块有自己的时区定义,所以我最终编写了自己的utcnow包装器:

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

当你需要将当前时间与PostgreSQL timestamptz进行比较时,只需使用pg_utcnow

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

我想比较本地天真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 :-(')

正确的解决方案是添加时区信息,例如,在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)

我知道有些人专门使用Django作为接口来抽象这种类型的数据库交互。Django提供了一些实用工具:

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

你需要建立一个基本的Django设置基础设施,即使你只是使用这种类型的接口(在设置中,你需要包括USE_TZ=True来获得一个感知datetime)。

就其本身而言,这可能远远不足以激励您使用Django作为接口,但还有许多其他好处。另一方面,如果您在这里遇到问题是因为您正在破坏Django应用程序(就像我一样),那么这可能会有所帮助……

这是一个非常简单和清晰的解决方案
两行代码

# 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

结论:你必须用相同的时间信息管理你的datetime变量

我也面临着同样的问题。经过一番寻找,我终于找到了解决办法。

问题是,当我们从model或form获取datetime对象时,它是抵消意识到,而如果我们通过系统获取时间,它是抵消天真

因此,我所做的就是使用timezone.now ()获得当前时间,并通过django。Utils导入时区导入时区,并将USE_TZ = True放入项目设置文件中。

我发现timezone.make_aware(datetime.datetime.now())在django中很有用(我在1.9.1)。不幸的是,你不能简单地让一个datetime对象感知偏移量,然后timetz()它。你必须创建一个datetime并基于它进行比较。

我想到了一个超简单的解决办法:

import datetime


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

它既适用于时区感知型datetime值,也适用于时区无知型datetime值。并且不需要额外的库或数据库解决方案。

你不需要性病资料库以外的任何东西

datetime.datetime.now().astimezone()

如果你只是更换了时区,它不会调整时间。如果你的系统已经是UTC,那么.replace(tz='UTC')就可以了。

>>> x=datetime.datetime.now()
datetime.datetime(2020, 11, 16, 7, 57, 5, 364576)


>>> print(x)
2020-11-16 07:57:05.364576


>>> print(x.astimezone())
2020-11-16 07:57:05.364576-07:00


>>> print(x.replace(tzinfo=datetime.timezone.utc)) # wrong
2020-11-16 07:57:05.364576+00:00

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

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