首页 文章

无法减去offset-naive和offset-aware datetimes

提问于
浏览
206

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

10 回答

  • 44

    我也遇到了同样的问题 . 然后我经过大量的搜索后找到了解决方案 .

    问题是,当我们从模型或表单中获取datetime对象时,它是 offset aware ,如果我们按系统获取时间,则为 offset naive .

    所以我做的是使用 timezone.now() 获取当前时间并通过 from django.utils import timezone 导入时区并将 USE_TZ = True 放入项目设置文件中 .

  • 1

    是否有一些紧迫的原因导致您无法处理PostgreSQL本身的年龄计算?就像是

    select *, age(timeStampField) as timeStampAge from myTable
    
  • 5

    你试图删除时区意识吗?

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

    naive = dt.replace(tzinfo=None)
    

    可能还需要添加时区转换 .

    编辑:请注意这个答案的年龄 . Python 3的答案如下 .

  • 0

    正确的解决方案是添加时区信息,例如,将当前时间作为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)
    
  • 12

    我知道有些人专门使用Django作为抽象这种类型的数据库交互的接口 . Django提供了可用于此的实用程序:

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

    您确实需要设置一个基本的Django设置基础结构,即使您只是使用这种类型的接口(在设置中,您需要包含 USE_TZ=True 以获得有意识的日期时间) .

    就其本身而言,这可能远远不足以激励您使用Django作为接口,但还有许多其他特权 . 另一方面,如果你因为你正在破坏你的Django应用程序(就像我一样)而在这里跌跌撞撞,那么也许这有助于......

  • 117

    This is a very simple and clear solution
    Two lines of code

    # 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
    

    您必须使用相同的时间信息管理日期时间变量

  • 4

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

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

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

  • 0

    我提出了一个超简单的解决方案:

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

    它适用于时区感知和时区初始日期时间值 . 并且不需要额外的库或数据库解决方法 .

  • 1

    我知道这已经过时了,但我想我会添加我的解决方案以防有人发现它有用 .

    我想将本地天真日期时间与来自时间服务器的识别日期时间进行比较 . 我基本上使用知道的datetime对象创建了一个新的天真日期时间对象 . 这有点像黑客,看起来不是很漂亮,但完成工作 .

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

    我发现 timezone.make_aware(datetime.datetime.now()) 在django中很有用(我只需要 datetime 对象可以识别偏移量,然后 timetz() 它 . 你必须制作一个 datetime 并根据它进行比较 .

相关问题