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


当前回答

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

import datetime

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

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

其他回答

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

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

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

这是一个非常简单明了的解决方案——两行代码

# 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变量

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

问题是,当我们从模型或表单获取datetime对象时,它是偏移量感知的,如果我们通过系统获取时间,它是偏移量无知的。

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