From 649b28eab6765cd6b2b40c779a18ecafc99b43d7 Mon Sep 17 00:00:00 2001 From: Lily Foote Date: Sun, 25 Sep 2022 13:32:05 +0100 Subject: [PATCH] Fixed #34070 -- Added subsecond support to Now() on SQLite and MySQL. --- django/db/backends/mysql/features.py | 2 +- django/db/models/functions/datetime.py | 13 +++++++++++++ docs/ref/models/database-functions.txt | 5 +++++ docs/releases/4.2.txt | 3 +++ tests/db_functions/datetime/test_now.py | 18 +++++++++++++++++- 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/django/db/backends/mysql/features.py b/django/db/backends/mysql/features.py index 2d5487446e..d5641215ca 100644 --- a/django/db/backends/mysql/features.py +++ b/django/db/backends/mysql/features.py @@ -81,7 +81,7 @@ class DatabaseFeatures(BaseDatabaseFeatures): "swedish_ci": f"{charset}_swedish_ci", } - test_now_utc_template = "UTC_TIMESTAMP" + test_now_utc_template = "UTC_TIMESTAMP(6)" @cached_property def django_test_skips(self): diff --git a/django/db/models/functions/datetime.py b/django/db/models/functions/datetime.py index f833c09973..939fa656d7 100644 --- a/django/db/models/functions/datetime.py +++ b/django/db/models/functions/datetime.py @@ -223,6 +223,19 @@ class Now(Func): compiler, connection, template="STATEMENT_TIMESTAMP()", **extra_context ) + def as_mysql(self, compiler, connection, **extra_context): + return self.as_sql( + compiler, connection, template="CURRENT_TIMESTAMP(6)", **extra_context + ) + + def as_sqlite(self, compiler, connection, **extra_context): + return self.as_sql( + compiler, + connection, + template="STRFTIME('%%Y-%%m-%%d %%H:%%M:%%f', 'NOW')", + **extra_context, + ) + class TruncBase(TimezoneMixin, Transform): kind = None diff --git a/docs/ref/models/database-functions.txt b/docs/ref/models/database-functions.txt index e9a0736b5b..bdbecec2e9 100644 --- a/docs/ref/models/database-functions.txt +++ b/docs/ref/models/database-functions.txt @@ -495,6 +495,11 @@ Usage example:: ``Now()`` uses ``STATEMENT_TIMESTAMP`` instead. If you need the transaction timestamp, use :class:`django.contrib.postgres.functions.TransactionNow`. +.. versionchanged:: 4.2 + + Support for microsecond precision on MySQL and millisecond precision on + SQLite were added. + ``Trunc`` --------- diff --git a/docs/releases/4.2.txt b/docs/releases/4.2.txt index 718f09b9dc..0c5492e125 100644 --- a/docs/releases/4.2.txt +++ b/docs/releases/4.2.txt @@ -223,6 +223,9 @@ Models the text value of a key, index, or path transform of :class:`~django.db.models.JSONField`. +* :class:`~django.db.models.functions.Now` now supports microsecond precision + on MySQL and millisecond precision on SQLite. + Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/db_functions/datetime/test_now.py b/tests/db_functions/datetime/test_now.py index 669a973be0..716c5744e9 100644 --- a/tests/db_functions/datetime/test_now.py +++ b/tests/db_functions/datetime/test_now.py @@ -1,6 +1,8 @@ from datetime import datetime, timedelta -from django.db.models.functions import Now +from django.db import connection +from django.db.models import TextField +from django.db.models.functions import Cast, Now from django.test import TestCase from django.utils import timezone @@ -47,3 +49,17 @@ class NowTests(TestCase): ["How to Time Travel"], lambda a: a.title, ) + + def test_microseconds(self): + Article.objects.create( + title="How to Django", + text=lorem_ipsum, + written=timezone.now(), + ) + now_string = ( + Article.objects.annotate(now_string=Cast(Now(), TextField())) + .get() + .now_string + ) + precision = connection.features.time_cast_precision + self.assertRegex(now_string, rf"^.*\.\d{{1,{precision}}}")