我正在使用SQLAlchemy与使用奇怪时间戳格式的远程数据库一起工作 - 它将时间戳存储为自时代以来的双精度毫秒。我想使用Python datetime对象的工作,所以我写在我的模型getter/setter方法,下面this gist:在执行查询之前将datetime转换为SQLAlchemy模型中的unix timestamp?
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import synonym
from sqlalchemy.dialects.mysql import DOUBLE
import datetime
Base = declarative_base()
class Table(Base):
__tablename__ = "table"
id = Column(Integer, primary_key=True)
_timestamp = Column("timestamp", DOUBLE(asdecimal=False))
@property
def timestamp(self):
return datetime.datetime.utcfromtimestamp(float(self._timestamp)/1000.)
@timestamp.setter
def timestamp(self, dt):
self._timestamp = float(dt.strftime("%s"))*1000.
timestamp = synonym('_timestamp', descriptor=timestamp)
这个伟大的工程插入新行到表中,从表对象的工作:
>>> table = session.query(Table).first()
<Table id=1>
>>> table.timestamp
datetime.datetime(2016, 6, 27, 16, 9, 3, 320000)
>>> table._timestamp
1467043743320.0
然而,它打破了,当我尝试在筛选表达式中使用日期时间:
>>> july = datetime.datetime(2016, 7, 1)
>>> old = session.query(Table).filter(Table.timestamp < july).first()
/lib/python2.7/site-packages/sqlalchemy/engine/default.py:450: Warning: Truncated incorrect DOUBLE value: '2016-07-01 00:00:00'
>>> july_flt = float(july.strftime("%s"))*1000.
>>> old = session.query(Table).filter(Table.timestamp < july_flt).first()
<Table id=1>
我想这是因为我的getter/setter方法适用ŧ o表类的实例,但不要改变类本身的行为。我试着用的,而不是一个代名词混合属性改写:
from sqlalchemy.ext.hybrid import hybrid_property
class Table(Base):
__tablename__ = "table"
id = Column(Integer, primary_key=True)
_timestamp = Column("timestamp", DOUBLE(asdecimal=False))
@hybrid_property
def timestamp(self):
return datetime.datetime.utcfromtimestamp(float(self._timestamp)/1000.)
@timestamp.setter
def timestamp(self, dt):
self._timestamp = float(dt.strftime("%s"))*1000.
再次,这与工作表的情况下,但未能对查询 - 现在它打我的getter方法,当我运行查询:
>>> july = datetime.datetime(2016, 7, 1)
>>> old = session.query(Table).filter(Table.timestamp < july).first()
Traceback:
File "models.py", line 42, in timestamp
return datetime.datetime.utcfromtimestamp(float(self._timestamp)/1000.)
TypeError: float() argument must be a string or a number
通过调试器,我可以看到getter正在接收Table._timestamp类(不是特定的Table._timestamp,而不是'7月')。
我看到我可以使用hybrid_property.expression装饰器来定义一个SQL表达式来将时间戳转换为日期时间,但我真正喜欢的是将日期时间转换为python侧的时间戳,然后使用时间戳运行查询。换句话说,我想在任何地方使用日期时间(包括在查询中),但是一切都用SQL方面的微秒时间戳完成。我怎样才能做到这一点?
谢谢!我会在今天下午尝试这个方法,一旦有效就接受答案。 Re:milli与micro,你是对的;这是我在数据库程序员的文档中发现的一个错误。回复:strftime,不幸的是我使用Python 2.7,并没有得到'datetime.timestamp()'方法。如果我只在本地机器上运行它,“strftime”方法是我的首选kludge :) – nrlakin
2.7解决方案'(dt - datetime(1970,1,1))/ timedelta(seconds = 1)'很容易也是:) – RazerM
是的,但它很冗长。如果我正在为服务器写一些东西,但是我不知道它将运行在哪个平台上,我会使用比'strftime'更安全的东西。奇怪的是,对于一个常见问题的所有2.7解决方案是如此不雅... – nrlakin