i try to get this Query running but it does not work like i expected.
In the table is a Date Field Formatted as Text (can't change it) and i need to filter this Column.
Dates looks like
11/03/2022 (d/m/Y)
My Query looks like
session.query(DBGEUK)\
.filter(DBGEUK.VALIDATOR == '58')\
.filter(func.CDate(DBGEUK.DATE) <= datetime.now())\
.all()
There is a total of 24 entry's. When i run the Query above and print out the DBGEUK.DATE datetime.now, this 9 entry's are my result.
27/03/2022 2022-03-28 19:06:49.465406
27/03/2022 2022-03-28 19:06:49.480988
27/03/2022 2022-03-28 19:06:49.480988
27/03/2022 2022-03-28 19:06:49.480988
28/03/2022 2022-03-28 19:06:49.480988
28/03/2022 2022-03-28 19:06:49.480988
28/03/2022 2022-03-28 19:06:49.480988
28/03/2022 2022-03-28 19:06:49.481612
28/03/2022 2022-03-28 19:06:49.481727
If i change the Query to greater then >= i got the other 15 entry's
04/03/2022 2022-03-28 19:09:09.030659
04/03/2022 2022-03-28 19:09:09.031659
04/03/2022 2022-03-28 19:09:09.031659
04/03/2022 2022-03-28 19:09:09.031659
04/03/2022 2022-03-28 19:09:09.031659
05/03/2022 2022-03-28 19:09:09.031659
05/03/2022 2022-03-28 19:09:09.031659
05/03/2022 2022-03-28 19:09:09.031659
05/03/2022 2022-03-28 19:09:09.032657
11/03/2022 2022-03-28 19:09:09.032657
12/03/2022 2022-03-28 19:09:09.032657
11/03/2022 2022-03-28 19:09:09.032657
11/03/2022 2022-03-28 19:09:09.032657
09/03/2022 2022-03-28 19:09:09.033654
09/03/2022 2022-03-28 19:09:09.033654
Thanks for your help in advanced.
CodePudding user response:
The CDate()
function tries to interpret date string literals according to the date formatting settings in the Windows control panel. With a "short date" setting of MM/dd/yyyy
, CDate("03/07/2022")
evaluates to March 7, 2022. With a "short date" setting of dd/MM/yyyy
, CDate("03/07/2022")
evaluates to July 3, 2022.
However, if the date string represents an invalid date then CDate()
will be "helpful" and return a valid date using the other format. In both cases above, CDate("14/03/2022")
will evaluate to March 14, 2022.
Unfortunately, this means that
- How the dates are interpreted depends on the Windows date format, which can vary from machine to machine and even from user to user on the same machine.
- The interpretation of dates can be inconsistent between ambiguous and unambiguous date strings.
Therefore in this case we need to avoid using CDate()
and parse the date string ourselves:
from datetime import datetime
from sqlalchemy import create_engine, Column, String, select, func
from sqlalchemy.engine import URL
from sqlalchemy.orm import declarative_base, Session
accdb_path = r"C:\Users\Public\test\sqlalchemy-access\gord_test.accdb"
connection_string = (
"DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};"
f"DBQ={accdb_path};"
"ExtendedAnsiSQL=1;"
)
connection_url = URL.create(
"access pyodbc", query={"odbc_connect": connection_string}
)
engine = create_engine(connection_url)
Base = declarative_base()
class DBGEUK(Base):
__tablename__ = "so71651145"
DATE = Column(String(10), primary_key=True)
def __repr__(self):
return f"<DBGEUK(DATE='{self.DATE}')>"
# create test environment
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
with Session(engine) as session:
# example data
session.add_all(
[
# How CDate() interprets the string
# based on Windows' short date format:
#
# dd/MM/yyyy MM/dd/yyyy
# ------------ ------------
DBGEUK(DATE="07/03/2022"), # Mar 7, 2022 Jul 3, 2022
DBGEUK(DATE="14/03/2022"), # Mar 14, 2022 Mar 14, 2022
DBGEUK(DATE="03/07/2022"), # Jul 3, 2022 Mar 7, 2022
DBGEUK(DATE="31/12/2022"), # Dec 31, 2022 Dec 31, 2022
]
)
session.commit()
# (for future readers of this answer)
print(datetime.now()) # 2022-03-29 08:44:00.512366
# original query
qry = select(DBGEUK).filter(func.CDate(DBGEUK.DATE) <= datetime.now())
results = session.execute(qry).all()
print(results)
# [(<DBGEUK(DATE='14/03/2022')>,), (<DBGEUK(DATE='03/07/2022')>,)]
#
# with Windows' short date format set to MM/dd/yyyy, CDate() interprets
# the second value as March 7, not July 3
# corrected query
qry = select(DBGEUK).filter(
func.DateSerial(
func.CInt(func.Mid(DBGEUK.DATE, 7, 4)), # year
func.CInt(func.Mid(DBGEUK.DATE, 4, 2)), # month
func.CInt(func.Mid(DBGEUK.DATE, 1, 2)), # day
)
<= datetime.now()
)
results = session.execute(qry).all()
print(results)
# [(<DBGEUK(DATE='07/03/2022')>,), (<DBGEUK(DATE='14/03/2022')>,)]
#
# all good