sqlalchemy: Incorrect results or errors when adding a datetime.timedelta() value to a column
Describe the bug When using pymssql and a timedelta is added to a column which has DateTime format, an additional 70 years added beside the specified value.
Column:
end_time = Column(DateTime, nullable=False)
Update:
session.query(Auction).filter_by(id=auction.id).update({Auction.end_time: Auction.end_time + datetime.timedelta(seconds=10)})
Expected behavior 10 seconds are added to the original end_time value.
To Reproduce Run the following code.
#!/usr/bin/python3
import datetime
import sqlalchemy.ext.declarative as dec
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy import Column, Integer, DateTime
from contextlib import contextmanager
engine = create_engine("mssql+pymssql://<user>:<password>@<ip>:1433/<db>", echo=True)
session_factory = sessionmaker(bind=engine)
DbSession = scoped_session(session_factory)
@contextmanager
def session_scope():
"""Provide a transactional scope around a series of operations."""
session = DbSession()
try:
yield session
session.commit()
except:
session.rollback()
raise
finally:
session.close()
DbSession.remove()
Base = dec.declarative_base()
class Auction(Base):
__tablename__ = "auction"
id = Column(Integer, primary_key=True, autoincrement=True)
end_time = Column(DateTime, nullable=False)
Auction.metadata.create_all(engine, checkfirst=True)
with session_scope() as session:
auction = Auction()
auction.end_time = datetime.datetime(2020, 10, 27, 9, 55, 31)
session.add(auction)
session.commit()
session.query(Auction).filter_by(id=auction.id).update({Auction.end_time: Auction.end_time + datetime.timedelta(seconds=10)})
session.commit()
modified_auction = session.query(Auction).filter_by(id=auction.id).first()
if modified_auction.end_time != datetime.datetime(2020, 10, 27, 9, 55, 31) + datetime.timedelta(seconds=10):
print("ERROR", modified_auction.end_time.isoformat())
Versions.
- OS: Ubuntu 20.04.1 LTS
- Python: Python 3.8.5 (default, Jul 28 2020, 12:59:40)
- SQLAlchemy: 1.3.19
- Database: Docker container from mcr.microsoft.com/mssql/server:2017-CU8-ubuntu image
- DBAPI: pymssql 2.1.5
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 15 (15 by maintainers)
Okay, thanks for the pointers. To be clear, I wasn’t suggesting a full implementation of +/- date arithmetic for drivers that don’t natively support it like psycopg2 does …
… I was looking for the most straightforward way to warn/raise if somebody tries it when the underlying database/DBAPI “doesn’t do that”.
mssql+pymssqlis actually the one particular case here because it returns an incorrect result without complaint; the other failing cases (mssql+pyodbc,mysql, andsqlite) will raise an exception which is a pretty good hint that the operation is not supported. 😉so as mentioned earlier we don’t implement date arithmetic operators. however this kind of issue could be prevented by at least having the operators that we implement for other systems, do something appropriate, like if dateadd is available, have the “+” sign render a dateadd, and for backends where we know we aren’t doing it, particularly SQLite where you need to convert both sides of an expression into an epoch to do date arithmetic, just raise an exception or emit a warning.
this is a lot of work for little positive result so it has not been prioritized for many years.
hey @gordthompson set synchronize_session=False and run that UPDATE again like that, just to see if the SQL part works. we don’t need to exercise the ORM part here.
I am able to reproduce your issue:
I will investigate further.