diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 6f8ca8980f..de69e5a35f 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -1682,7 +1682,8 @@ class DurationField(Field): return value if value is None: return None - return value.total_seconds() * 1000000 + # Discard any fractional microseconds due to floating point arithmetic. + return int(round(value.total_seconds() * 1000000)) def get_db_converters(self, connection): converters = [] diff --git a/docs/releases/1.8.12.txt b/docs/releases/1.8.12.txt index 26735b8278..0052a90b0d 100644 --- a/docs/releases/1.8.12.txt +++ b/docs/releases/1.8.12.txt @@ -12,3 +12,6 @@ Bugfixes * Made ``MultiPartParser`` ignore filenames that normalize to an empty string to fix crash in ``MemoryFileUploadHandler`` on specially crafted user input (:ticket:`26325`). + +* Fixed data loss on SQLite where ``DurationField`` values with fractional + seconds could be saved as ``None`` (:ticket:`26324`). diff --git a/docs/releases/1.9.5.txt b/docs/releases/1.9.5.txt index d14b1ac98e..55fd794d78 100644 --- a/docs/releases/1.9.5.txt +++ b/docs/releases/1.9.5.txt @@ -16,3 +16,6 @@ Bugfixes * Fixed a race condition in ``BaseCache.get_or_set()`` (:ticket:`26332`). It now returns the ``default`` value instead of ``False`` if there's an error when trying to add the value to the cache. + +* Fixed data loss on SQLite where ``DurationField`` values with fractional + seconds could be saved as ``None`` (:ticket:`26324`). diff --git a/tests/model_fields/test_durationfield.py b/tests/model_fields/test_durationfield.py index fb26baadc9..82c5c875bf 100644 --- a/tests/model_fields/test_durationfield.py +++ b/tests/model_fields/test_durationfield.py @@ -22,6 +22,12 @@ class TestSaveLoad(TestCase): loaded = NullDurationModel.objects.get() self.assertEqual(loaded.field, None) + def test_fractional_seconds(self): + value = datetime.timedelta(seconds=2.05) + d = DurationModel.objects.create(field=value) + d.refresh_from_db() + self.assertEqual(d.field, value) + class TestQuerying(TestCase):