-
-
Notifications
You must be signed in to change notification settings - Fork 33.1k
Fixed #34070 -- Added subsecond support to Now() on SQLite and MySQL. #16111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@LilyFoote Thanks 👍 Should we update also
Can we add a regression test? For example by checking microseconds in |
I don't think it particularly matters - it's only used in the Thinking about it a bit more, it's weird to me that this is implemented as a feature at all, since it's purely for this one test class. |
This is a bit tricky - the natural test to write checks that the My other idea is to make an assertion before we convert the database value to a python |
1 in a million flaky is almost worse than 1 in 2 flaky 😅 Perhaps you can cast the result to a string and check it has 6 trailing digits of precision? now_string = Something.objects.annotate(
now_string=Cast(Now(), TextField())
).get().now_string
self.assertRegex(now_string, "^.*\.\d{6}") You'd need to check that MySQL doesn't do like Python and not output the digits if it's 0 microseconds... Plus the test may need to be MySQL specific in case other DB's have different string formats. |
It turns out sqlite doesn't do microsecond precision. There's a way to get millisecond precision: |
Thinking about it a bit more, I think we do want millisecond precision on sqlite, since it's better than the status quo. |
buildbot, test on oracle. |
👍👍👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@LilyFoote Thanks 👍
0489f87
to
d37c5bd
Compare
d37c5bd
to
649b28e
Compare
return self.as_sql( | ||
compiler, | ||
connection, | ||
template="STRFTIME('%%Y-%%m-%%d %%H:%%M:%%f', 'NOW')", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@felixxm These needed to be %%%%
: https://docs.djangoproject.com/en/4.1/ref/models/expressions/#django.db.models.Func.template
I'm looking into writing a standalone test that proves this, but it is currently causing the sqlite tests to break on #16092.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, maybe this is actually a bug on the db defaults side...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed that it's documented, however both versions works on SQLite as it has a custom SQLiteCursorWrapper
:
django/django/db/backends/sqlite3/base.py
Lines 355 to 376 in 649b28e
FORMAT_QMARK_REGEX = _lazy_re_compile(r"(?<!%)%s") | |
class SQLiteCursorWrapper(Database.Cursor): | |
""" | |
Django uses "format" style placeholders, but pysqlite2 uses "qmark" style. | |
This fixes it -- but note that if you want to use a literal "%s" in a query, | |
you'll need to use "%%s". | |
""" | |
def execute(self, query, params=None): | |
if params is None: | |
return Database.Cursor.execute(self, query) | |
query = self.convert_query(query) | |
return Database.Cursor.execute(self, query, params) | |
def executemany(self, query, param_list): | |
query = self.convert_query(query) | |
return Database.Cursor.executemany(self, query, param_list) | |
def convert_query(self, query): | |
return FORMAT_QMARK_REGEX.sub("?", query).replace("%%", "%") |
and the format string doesn't contain
%s
. I'm not sure if it's worth changing 🤔
Extracted from #16092 as suggested in #16092 (comment).