How to compare dates in sqlalchemy?
Question:
I have the following simple setup, where fromDate and toDate are strings on the format “YYYY-MM-DD”:
class SomeType(Base):
date = Column(DateTime)
def findAll(fromDate, toDate):
return session.query(SomeType).filter(SomeType.date >= fromDate, SomeType.date <= toDate).all()
The problem is that it doesn’t find what I want it to find unless I modify the input dates like this:
def findAll(fromDate, toDate):
fromDate = fromDate + " 00:00"
toDate = toDate + " 24:00"
return session.query(SomeType).filter(SomeType.date >= fromDate, SomeType.date <= toDate).all()
But that doesn’t look good. Any ideas on how I can do this the right way?
Answers:
How about using datetime.datetime
objects instead of strings for fromDate
, toDate
?
from datetime import datetime, timedelta
def findAll(fromDate, toDate):
fromDate = datetime.strptime(fromDate, '%Y-%m-%d')
toDate = datetime.strptime(toDate, '%Y-%m-%d') + timedelta(days=1)
return session.query(SomeType).filter(
SomeType.date >= fromDate,
SomeType.date < toDate).all()
The problem is that your SomeType.date
column is not simple date
, but is datetime
column, so it contains also a time component.
This type mismatch is the cause of your problem. If this is the case then following should work:
session.query(SomeType).filter(func.date(SomeType.date) >= fromDate, func.date(SomeType.date) <= toDate).all()
where we basically cast
datetime
to date
using DATE(...)
function of MySql.
However, I would probably also prefer working with date(time)
data types instead of strings. You are just lucky that most databases implicitly allow parsing of ISO-compliant string representations of DATEs.
I know this is old, but while trying to find my answer, I found datetime.combine
you can do
select(SomeTable)
.filter( SomeTable.datetime_issued >= datetime.combine(start_date, time.min),
SomeTable.datetime_issued <= datetime.combine(end_date, time.max))
datetime.combine will combine date and time into datetime
https://docs.python.org/3/library/datetime.html#datetime.datetime.combine
When combining, you should use time.min, time.max which will give you min and max time
print(combine(date.today(), time.min), combine(date.today(), time.max))
This will print
2022-10-14 00:00:00, 2022-10-14 23:59:59.999999
https://docs.python.org/3/library/datetime.html#datetime.time.max
I have the following simple setup, where fromDate and toDate are strings on the format “YYYY-MM-DD”:
class SomeType(Base):
date = Column(DateTime)
def findAll(fromDate, toDate):
return session.query(SomeType).filter(SomeType.date >= fromDate, SomeType.date <= toDate).all()
The problem is that it doesn’t find what I want it to find unless I modify the input dates like this:
def findAll(fromDate, toDate):
fromDate = fromDate + " 00:00"
toDate = toDate + " 24:00"
return session.query(SomeType).filter(SomeType.date >= fromDate, SomeType.date <= toDate).all()
But that doesn’t look good. Any ideas on how I can do this the right way?
How about using datetime.datetime
objects instead of strings for fromDate
, toDate
?
from datetime import datetime, timedelta
def findAll(fromDate, toDate):
fromDate = datetime.strptime(fromDate, '%Y-%m-%d')
toDate = datetime.strptime(toDate, '%Y-%m-%d') + timedelta(days=1)
return session.query(SomeType).filter(
SomeType.date >= fromDate,
SomeType.date < toDate).all()
The problem is that your SomeType.date
column is not simple date
, but is datetime
column, so it contains also a time component.
This type mismatch is the cause of your problem. If this is the case then following should work:
session.query(SomeType).filter(func.date(SomeType.date) >= fromDate, func.date(SomeType.date) <= toDate).all()
where we basically cast
datetime
to date
using DATE(...)
function of MySql.
However, I would probably also prefer working with date(time)
data types instead of strings. You are just lucky that most databases implicitly allow parsing of ISO-compliant string representations of DATEs.
I know this is old, but while trying to find my answer, I found datetime.combine
you can do
select(SomeTable)
.filter( SomeTable.datetime_issued >= datetime.combine(start_date, time.min),
SomeTable.datetime_issued <= datetime.combine(end_date, time.max))
datetime.combine will combine date and time into datetime
https://docs.python.org/3/library/datetime.html#datetime.datetime.combine
When combining, you should use time.min, time.max which will give you min and max time
print(combine(date.today(), time.min), combine(date.today(), time.max))
This will print
2022-10-14 00:00:00, 2022-10-14 23:59:59.999999
https://docs.python.org/3/library/datetime.html#datetime.time.max