diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index f0e184dde31..fcdee1bbd39 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -79,7 +79,7 @@ def adapt_datetime_with_timezone_support(value, conv): default_timezone = timezone.get_default_timezone() value = timezone.make_aware(value, default_timezone) value = value.astimezone(timezone.utc).replace(tzinfo=None) - return Thing2Literal(value.strftime("%Y-%m-%d %H:%M:%S"), conv) + return Thing2Literal(value.strftime("%Y-%m-%d %H:%M:%S.%f"), conv) # MySQLdb-1.2.1 returns TIME columns as timedelta -- they are more like # timedelta in terms of actual behavior as they are signed and include days -- @@ -175,7 +175,6 @@ class DatabaseFeatures(BaseDatabaseFeatures): supports_forward_references = False # XXX MySQL DB-API drivers currently fail on binary data on Python 3. supports_binary_field = six.PY2 - supports_microsecond_precision = False supports_regex_backreferencing = False supports_date_lookup_using_string = False can_introspect_binary_field = False @@ -210,6 +209,10 @@ class DatabaseFeatures(BaseDatabaseFeatures): "Confirm support for introspected foreign keys" return self._mysql_storage_engine != 'MyISAM' + @cached_property + def supports_microsecond_precision(self): + return self.connection.mysql_version >= (5, 6, 4) + @cached_property def has_zoneinfo_database(self): # MySQL accepts full time zones names (eg. Africa/Nairobi) but rejects diff --git a/django/db/backends/mysql/creation.py b/django/db/backends/mysql/creation.py index fd3a595eb48..40d9251235a 100644 --- a/django/db/backends/mysql/creation.py +++ b/django/db/backends/mysql/creation.py @@ -1,4 +1,5 @@ from django.db.backends.creation import BaseDatabaseCreation +from django.utils.functional import cached_property class DatabaseCreation(BaseDatabaseCreation): @@ -6,7 +7,7 @@ class DatabaseCreation(BaseDatabaseCreation): # types, as strings. Column-type strings can contain format strings; they'll # be interpolated against the values of Field.__dict__ before being output. # If a column type is set to None, it won't be included in the output. - data_types = { + _data_types = { 'AutoField': 'integer AUTO_INCREMENT', 'BinaryField': 'longblob', 'BooleanField': 'bool', @@ -33,6 +34,13 @@ class DatabaseCreation(BaseDatabaseCreation): 'UUIDField': 'char(32)', } + @cached_property + def data_types(self): + if self.connection.features.supports_microsecond_precision: + return dict(self._data_types, DateTimeField='datetime(6)', TimeField='time(6)') + else: + return self._data_types + def sql_table_creation_suffix(self): suffix = [] test_settings = self.connection.settings_dict['TEST'] diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt index cbc75d6a9ca..63cb5f279ea 100644 --- a/docs/ref/databases.txt +++ b/docs/ref/databases.txt @@ -496,11 +496,32 @@ for the field. This affects :class:`~django.db.models.CharField`, :class:`~django.db.models.SlugField` and :class:`~django.db.models.CommaSeparatedIntegerField`. -DateTime fields -~~~~~~~~~~~~~~~ +.. _mysql-fractional-seconds: -MySQL does not store fractions of seconds. Fractions of seconds are truncated -to zero when the time is stored. +Fractional seconds support for Time and DateTime fields +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +MySQL 5.6.4 and later can store fractional seconds, provided that the +column definition includes a fractional indication (e.g. ``DATETIME(6)``). +Earlier versions do not support them at all. + +Django will not upgrade existing columns to include fractional seconds if the +database server supports it. If you want to enable them on an existing database, +it's up to you to either manually update the column on the target database, by +executing a command like:: + + ALTER TABLE `your_table` MODIFY `your_datetime_column` DATETIME(6) + +or using a :class:`~django.db.migrations.operations.RunSQL` operation in a +:ref:`data migration `. + +.. versionchanged:: 1.8 + + Previously, Django truncated fractional seconds from ``datetime`` and + ``time`` values when using the MySQL backend. Now it lets the database + decide whether it should drop that part of the value or not. By default, new + ``DateTimeField`` or ``TimeField`` columns are now created with fractional + seconds support on MySQL 5.6.4 or later. ``TIMESTAMP`` columns ~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt index b37676008bb..eef836f6aab 100644 --- a/docs/releases/1.8.txt +++ b/docs/releases/1.8.txt @@ -166,7 +166,9 @@ Database backends * The MySQL backend no longer strips microseconds from ``datetime`` values as MySQL 5.6.4 and up supports fractional seconds depending on the declaration of the datetime field (when ``DATETIME`` includes fractional precision greater - than 0). + than 0). New datetime database columns created with Django 1.8 and MySQL 5.6.4 + and up will support microseconds. See the :ref:`MySQL database notes + ` for more details. Email ^^^^^