У нас есть базы данных sqlite, и даты действительно хранятся в формате Excel (для этого есть веская причина; это стандартное представление нашей системы, и базы данных sqlite могут быть доступны для нескольких языков / систем)
В последние месяцы мы с большим успехом внедряем Python в микс, и SQLAlchemy является его частью.Особенно ценится способность уровня dbapi sqlite3 быстро связывать пользовательские функции Python, где SQLite не хватает данной функции SQL.
Я написал декоратор типа ExcelDateTime, и это прекрасно работает при получении наборов результатов из баз данных sqlite;Python возвращает правильные даты и обратно.
Однако у меня есть реальная проблема с привязкой пользовательских функций python, которые ожидают, что входные параметры будут датами Python;Я бы подумал, что это было то, для чего был bindparam, но я явно что-то упускаю, так как я не могу заставить этот сценарий работать.К сожалению, изменение функций для преобразования из даты-даты в Excel в дату-время Python не является опцией, и также не изменяется представление даты-времени в базе данных, поскольку к ней могут обращаться несколько систем / языков.
Кодниже приведен автономный пример, который можно запустить «как есть», и он представляет проблему.Пользовательская функция «get_month» создается, но завершается сбоем, поскольку получает необработанные данные, а не данные, преобразованные по типу, из столбца «Born».В конце вы можете увидеть, что я пробовал до сих пор, и ошибки, которые он выплевывает ...
Разве то, что я пытаюсь сделать, невозможно?Или есть другой способ гарантировать, что связанная функция получает соответствующий тип python?Это единственная проблема, которую я до сих пор не смог преодолеть, было бы здорово найти решение!
import sqlalchemy.types as types
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData
from sqlalchemy.sql.expression import bindparam
from sqlalchemy.sql import select, text
from sqlalchemy.interfaces import PoolListener
import datetime
# setup type decorator for excel<->python date conversions
class ExcelDateTime( types.TypeDecorator ):
impl = types.FLOAT
def process_result_value( self, value, dialect ):
lxdays = int( value )
lxsecs = int( round((value-lxdays) * 86400.0) )
if lxsecs == 86400:
lxsecs = 0
lxdays += 1
return ( datetime.datetime.fromordinal(lxdays+693594)
+ datetime.timedelta(seconds=lxsecs) )
def process_bind_param( self, value, dialect ):
if( value < 200000 ): # already excel float?
return value
elif( isinstance(value,datetime.date) ):
return value.toordinal() - 693594.0
elif( isinstance(value,datetime.datetime) ):
date_part = value.toordinal() - 693594.0
time_part = ((value.hour*3600) + (value.minute*60) + value.second) / 86400.0
return date_part + time_part # time part = day fraction
# create sqlite memory db via sqlalchemy
def get_month( dt ):
return dt.month
class ConnectionFactory( PoolListener ):
def connect( self, dbapi_con, con_record ):
dbapi_con.create_function( 'GET_MONTH',1,get_month )
eng = create_engine('sqlite:///:memory:',listeners=[ConnectionFactory()])
eng.dialect.dbapi.enable_callback_tracebacks( 1 ) # show better errors from user functions
meta = MetaData()
birthdays = Table('Birthdays', meta, Column('Name',String,primary_key=True), Column('Born',ExcelDateTime), Column('BirthMonth',Integer))
meta.create_all(eng)
dbconn = eng.connect()
dbconn.execute( "INSERT INTO Birthdays VALUES('Jimi Hendrix',15672,NULL)" )
# demonstrate the type decorator works and we get proper datetimes out
res = dbconn.execute( select([birthdays]) )
tuple(res)
# >>> ((u'Jimi Hendrix', datetime.datetime(1942, 11, 27, 0, 0)),)
# simple attempt (blows up with "AttributeError: 'float' object has no attribute 'month'")
dbconn.execute( text("UPDATE Birthdays SET BirthMonth = GET_MONTH(Born)") )
# more involved attempt( blows up with "InterfaceError: (InterfaceError) Error binding parameter 0 - probably unsupported type")
dbconn.execute( text( "UPDATE Birthdays SET BirthMonth = GET_MONTH(:Born)",
bindparams=[bindparam('Born',ExcelDateTime)],
typemap={'Born':ExcelDateTime} ),
Born=birthdays.c.Born )
Большое спасибо.