无法减去时区无关和时区相关的日期时间

497 投票
12 回答
458710 浏览
提问于 2025-04-15 11:17

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

12 个回答

79

我知道有些人专门用Django来简化与数据库的交互。Django提供了一些工具,可以用来实现这个功能:

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

即使你只是想用这种接口,也需要先设置一个基本的Django配置。在设置中,你需要加上USE_TZ=True,这样才能正确处理带时区的日期时间。

光有这些可能还不足以让你觉得使用Django作为接口很有吸引力,但它还有很多其他好处。另一方面,如果你是因为搞砸了自己的Django应用而来到这里(就像我当初一样),那么这些信息或许能帮到你……

413

正确的解决办法是添加时区信息,比如在Python 3中获取当前时间作为一个带时区的日期时间对象:

from datetime import datetime, timezone

now = datetime.now(timezone.utc)

在旧版本的Python中,你可以自己定义一个utc时区信息对象(这是来自日期时间文档的例子):

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)
470

你有没有尝试过去掉时区的相关信息?

来自 http://pytz.sourceforge.net/

naive = dt.replace(tzinfo=None)

可能还需要添加时区转换的功能。

编辑:请注意这个回答的时间。下面有一个关于在Python 3中添加时区信息,而不是去掉它的回答。 https://stackoverflow.com/a/25662061/93380

撰写回答