Skip to content

Commit a80903b

Browse files
committed
Removed DatabaseFeatures.supports_microsecond_precision.
MySQL 5.5 (refs #28552) was the last database to use it.
1 parent 8a17684 commit a80903b

File tree

8 files changed

+89
-199
lines changed

8 files changed

+89
-199
lines changed

django/db/backends/base/features.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,6 @@ class BaseDatabaseFeatures:
7070
# by returning the type used to store duration field?
7171
supports_temporal_subtraction = False
7272

73-
# Do time/datetime fields have microsecond precision?
74-
supports_microsecond_precision = True
75-
7673
# Does the __regex lookup support backreferencing and grouping?
7774
supports_regex_backreferencing = True
7875

tests/basic/tests.py

Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
from django.db.models.manager import BaseManager
77
from django.db.models.query import EmptyQuerySet, QuerySet
88
from django.test import (
9-
SimpleTestCase, TestCase, TransactionTestCase, skipIfDBFeature,
10-
skipUnlessDBFeature,
9+
SimpleTestCase, TestCase, TransactionTestCase, skipUnlessDBFeature,
1110
)
1211
from django.utils.translation import gettext_lazy
1312

@@ -164,43 +163,14 @@ def test_not_equal_and_equal_operators_behave_as_expected_on_instances(self):
164163

165164
self.assertNotEqual(Article.objects.get(id__exact=a1.id), Article.objects.get(id__exact=a2.id))
166165

167-
@skipUnlessDBFeature('supports_microsecond_precision')
168166
def test_microsecond_precision(self):
169-
# In PostgreSQL, microsecond-level precision is available.
170167
a9 = Article(
171168
headline='Article 9',
172169
pub_date=datetime(2005, 7, 31, 12, 30, 45, 180),
173170
)
174171
a9.save()
175172
self.assertEqual(Article.objects.get(pk=a9.pk).pub_date, datetime(2005, 7, 31, 12, 30, 45, 180))
176173

177-
@skipIfDBFeature('supports_microsecond_precision')
178-
def test_microsecond_precision_not_supported(self):
179-
# In MySQL, microsecond-level precision isn't always available. You'll
180-
# lose microsecond-level precision once the data is saved.
181-
a9 = Article(
182-
headline='Article 9',
183-
pub_date=datetime(2005, 7, 31, 12, 30, 45, 180),
184-
)
185-
a9.save()
186-
self.assertEqual(
187-
Article.objects.get(id__exact=a9.id).pub_date,
188-
datetime(2005, 7, 31, 12, 30, 45),
189-
)
190-
191-
@skipIfDBFeature('supports_microsecond_precision')
192-
def test_microsecond_precision_not_supported_edge_case(self):
193-
# In MySQL, microsecond-level precision isn't always available. You'll
194-
# lose microsecond-level precision once the data is saved.
195-
a = Article.objects.create(
196-
headline='Article',
197-
pub_date=datetime(2008, 12, 31, 23, 59, 59, 999999),
198-
)
199-
self.assertEqual(
200-
Article.objects.get(pk=a.pk).pub_date,
201-
datetime(2008, 12, 31, 23, 59, 59),
202-
)
203-
204174
def test_manually_specify_primary_key(self):
205175
# You can manually specify the primary key when creating a new object.
206176
a101 = Article(
@@ -667,14 +637,10 @@ def _update(self, *args, **kwargs):
667637

668638

669639
class ModelRefreshTests(TestCase):
670-
def _truncate_ms(self, val):
671-
# MySQL < 5.6.4 removes microseconds from the datetimes which can cause
672-
# problems when comparing the original value to that loaded from DB
673-
return val - timedelta(microseconds=val.microsecond)
674640

675641
def test_refresh(self):
676-
a = Article.objects.create(pub_date=self._truncate_ms(datetime.now()))
677-
Article.objects.create(pub_date=self._truncate_ms(datetime.now()))
642+
a = Article.objects.create(pub_date=datetime.now())
643+
Article.objects.create(pub_date=datetime.now())
678644
Article.objects.filter(pk=a.pk).update(headline='new headline')
679645
with self.assertNumQueries(1):
680646
a.refresh_from_db()
@@ -722,7 +688,7 @@ def test_refresh_null_fk(self):
722688
self.assertEqual(s2.selfref, s1)
723689

724690
def test_refresh_unsaved(self):
725-
pub_date = self._truncate_ms(datetime.now())
691+
pub_date = datetime.now()
726692
a = Article.objects.create(pub_date=pub_date)
727693
a2 = Article(id=a.pk)
728694
with self.assertNumQueries(1):
@@ -742,6 +708,6 @@ def test_refresh_fk_on_delete_set_null(self):
742708
self.assertIsNone(s1.article)
743709

744710
def test_refresh_no_fields(self):
745-
a = Article.objects.create(pub_date=self._truncate_ms(datetime.now()))
711+
a = Article.objects.create(pub_date=datetime.now())
746712
with self.assertNumQueries(0):
747713
a.refresh_from_db(fields=[])

tests/db_functions/test_datetime.py

Lines changed: 60 additions & 67 deletions
Large diffs are not rendered by default.

tests/db_functions/tests.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@
2020
tempor incididunt ut labore et dolore magna aliqua."""
2121

2222

23-
def truncate_microseconds(value):
24-
return value if connection.features.supports_microsecond_precision else value.replace(microsecond=0)
25-
26-
2723
class FunctionTests(TestCase):
2824

2925
def test_coalesce(self):
@@ -121,7 +117,7 @@ def test_greatest(self):
121117
articles = Article.objects.annotate(
122118
last_updated=Greatest('written', 'published'),
123119
)
124-
self.assertEqual(articles.first().last_updated, truncate_microseconds(now))
120+
self.assertEqual(articles.first().last_updated, now)
125121

126122
@skipUnlessDBFeature('greatest_least_ignores_nulls')
127123
def test_greatest_ignores_null(self):
@@ -174,7 +170,7 @@ def test_greatest_coalesce_workaround_mysql(self):
174170
Coalesce('published', past_sql),
175171
),
176172
)
177-
self.assertEqual(articles.first().last_updated, truncate_microseconds(now))
173+
self.assertEqual(articles.first().last_updated, now)
178174

179175
def test_greatest_all_null(self):
180176
Article.objects.create(title="Testing with Django", written=timezone.now())
@@ -225,7 +221,7 @@ def test_least(self):
225221
articles = Article.objects.annotate(
226222
first_updated=Least('written', 'published'),
227223
)
228-
self.assertEqual(articles.first().first_updated, truncate_microseconds(before))
224+
self.assertEqual(articles.first().first_updated, before)
229225

230226
@skipUnlessDBFeature('greatest_least_ignores_nulls')
231227
def test_least_ignores_null(self):
@@ -278,7 +274,7 @@ def test_least_coalesce_workaround_mysql(self):
278274
Coalesce('published', future_sql),
279275
),
280276
)
281-
self.assertEqual(articles.first().last_updated, truncate_microseconds(now))
277+
self.assertEqual(articles.first().last_updated, now)
282278

283279
def test_least_all_null(self):
284280
Article.objects.create(title="Testing with Django", written=timezone.now())

tests/expressions/tests.py

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,19 +1028,16 @@ def setUpTestData(cls):
10281028

10291029
# e1: started one day after assigned, tiny duration, data
10301030
# set so that end time has no fractional seconds, which
1031-
# tests an edge case on sqlite. This Experiment is only
1032-
# included in the test data when the DB supports microsecond
1033-
# precision.
1034-
if connection.features.supports_microsecond_precision:
1035-
delay = datetime.timedelta(1)
1036-
end = stime + delay + delta1
1037-
e1 = Experiment.objects.create(
1038-
name='e1', assigned=sday, start=stime + delay, end=end,
1039-
completed=end.date(), estimated_time=delta1,
1040-
)
1041-
cls.deltas.append(delta1)
1042-
cls.delays.append(e1.start - datetime.datetime.combine(e1.assigned, midnight))
1043-
cls.days_long.append(e1.completed - e1.assigned)
1031+
# tests an edge case on sqlite.
1032+
delay = datetime.timedelta(1)
1033+
end = stime + delay + delta1
1034+
e1 = Experiment.objects.create(
1035+
name='e1', assigned=sday, start=stime + delay, end=end,
1036+
completed=end.date(), estimated_time=delta1,
1037+
)
1038+
cls.deltas.append(delta1)
1039+
cls.delays.append(e1.start - datetime.datetime.combine(e1.assigned, midnight))
1040+
cls.days_long.append(e1.completed - e1.assigned)
10441041

10451042
# e2: started three days after assigned, small duration
10461043
end = stime + delta2
@@ -1144,8 +1141,6 @@ def test_date_comparison(self):
11441141
def test_mixed_comparisons1(self):
11451142
for i in range(len(self.delays)):
11461143
delay = self.delays[i]
1147-
if not connection.features.supports_microsecond_precision:
1148-
delay = datetime.timedelta(delay.days, delay.seconds)
11491144
test_set = [e.name for e in Experiment.objects.filter(assigned__gt=F('start') - delay)]
11501145
self.assertEqual(test_set, self.expnames[:i])
11511146

@@ -1213,27 +1208,21 @@ def test_date_subtraction(self):
12131208
self.assertEqual(at_least_120_days, {'e5'})
12141209

12151210
less_than_5_days = {e.name for e in queryset.filter(completion_duration__lt=datetime.timedelta(days=5))}
1216-
expected = {'e0', 'e2'}
1217-
if connection.features.supports_microsecond_precision:
1218-
expected.add('e1')
1219-
self.assertEqual(less_than_5_days, expected)
1211+
self.assertEqual(less_than_5_days, {'e0', 'e1', 'e2'})
12201212

12211213
@skipUnlessDBFeature('supports_temporal_subtraction')
12221214
def test_time_subtraction(self):
1223-
if connection.features.supports_microsecond_precision:
1224-
time = datetime.time(12, 30, 15, 2345)
1225-
timedelta = datetime.timedelta(hours=1, minutes=15, seconds=15, microseconds=2345)
1226-
else:
1227-
time = datetime.time(12, 30, 15)
1228-
timedelta = datetime.timedelta(hours=1, minutes=15, seconds=15)
1229-
Time.objects.create(time=time)
1215+
Time.objects.create(time=datetime.time(12, 30, 15, 2345))
12301216
queryset = Time.objects.annotate(
12311217
difference=ExpressionWrapper(
12321218
F('time') - Value(datetime.time(11, 15, 0), output_field=models.TimeField()),
12331219
output_field=models.DurationField(),
12341220
)
12351221
)
1236-
self.assertEqual(queryset.get().difference, timedelta)
1222+
self.assertEqual(
1223+
queryset.get().difference,
1224+
datetime.timedelta(hours=1, minutes=15, seconds=15, microseconds=2345)
1225+
)
12371226

12381227
@skipUnlessDBFeature('supports_temporal_subtraction')
12391228
def test_datetime_subtraction(self):
@@ -1274,10 +1263,9 @@ def test_negative_timedelta_update(self):
12741263
new_start=F('start_sub_hours') + datetime.timedelta(days=-2),
12751264
)
12761265
expected_start = datetime.datetime(2010, 6, 23, 9, 45, 0)
1277-
if connection.features.supports_microsecond_precision:
1278-
# subtract 30 microseconds
1279-
experiments = experiments.annotate(new_start=F('new_start') + datetime.timedelta(microseconds=-30))
1280-
expected_start += datetime.timedelta(microseconds=+746970)
1266+
# subtract 30 microseconds
1267+
experiments = experiments.annotate(new_start=F('new_start') + datetime.timedelta(microseconds=-30))
1268+
expected_start += datetime.timedelta(microseconds=+746970)
12811269
experiments.update(start=F('new_start'))
12821270
e0 = Experiment.objects.get(name='e0')
12831271
self.assertEqual(e0.start, expected_start)

tests/m2m_through/tests.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from datetime import datetime
22
from operator import attrgetter
33

4-
from django.test import TestCase, skipUnlessDBFeature
4+
from django.test import TestCase
55

66
from .models import (
77
CustomMembership, Employee, Event, Friendship, Group, Ingredient,
@@ -196,7 +196,6 @@ def test_query_model_by_attribute_name_of_related_model(self):
196196
attrgetter("name")
197197
)
198198

199-
@skipUnlessDBFeature('supports_microsecond_precision')
200199
def test_order_by_relational_field_through_model(self):
201200
CustomMembership.objects.create(person=self.jim, group=self.rock)
202201
CustomMembership.objects.create(person=self.bob, group=self.rock)

tests/model_fields/test_datetimefield.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ def test_timefield_to_python_microseconds(self):
2424
self.assertEqual(f.to_python('01:02:03.000004'), datetime.time(1, 2, 3, 4))
2525
self.assertEqual(f.to_python('01:02:03.999999'), datetime.time(1, 2, 3, 999999))
2626

27-
@skipUnlessDBFeature('supports_microsecond_precision')
2827
def test_datetimes_save_completely(self):
2928
dat = datetime.date(2014, 3, 12)
3029
datetim = datetime.datetime(2014, 3, 12, 21, 22, 23, 240000)

tests/timezones/tests.py

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,12 @@ def test_naive_datetime(self):
5656
event = Event.objects.get()
5757
self.assertEqual(event.dt, dt)
5858

59-
@skipUnlessDBFeature('supports_microsecond_precision')
6059
def test_naive_datetime_with_microsecond(self):
6160
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
6261
Event.objects.create(dt=dt)
6362
event = Event.objects.get()
6463
self.assertEqual(event.dt, dt)
6564

66-
@skipIfDBFeature('supports_microsecond_precision')
67-
def test_naive_datetime_with_microsecond_unsupported(self):
68-
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
69-
Event.objects.create(dt=dt)
70-
event = Event.objects.get()
71-
# microseconds are lost during a round-trip in the database
72-
self.assertEqual(event.dt, dt.replace(microsecond=0))
73-
7465
@skipUnlessDBFeature('supports_timezones')
7566
def test_aware_datetime_in_local_timezone(self):
7667
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
@@ -81,7 +72,6 @@ def test_aware_datetime_in_local_timezone(self):
8172
self.assertEqual(event.dt.replace(tzinfo=EAT), dt)
8273

8374
@skipUnlessDBFeature('supports_timezones')
84-
@skipUnlessDBFeature('supports_microsecond_precision')
8575
def test_aware_datetime_in_local_timezone_with_microsecond(self):
8676
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
8777
Event.objects.create(dt=dt)
@@ -90,18 +80,6 @@ def test_aware_datetime_in_local_timezone_with_microsecond(self):
9080
# interpret the naive datetime in local time to get the correct value
9181
self.assertEqual(event.dt.replace(tzinfo=EAT), dt)
9282

93-
# This combination actually never happens.
94-
@skipUnlessDBFeature('supports_timezones')
95-
@skipIfDBFeature('supports_microsecond_precision')
96-
def test_aware_datetime_in_local_timezone_with_microsecond_unsupported(self):
97-
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
98-
Event.objects.create(dt=dt)
99-
event = Event.objects.get()
100-
self.assertIsNone(event.dt.tzinfo)
101-
# interpret the naive datetime in local time to get the correct value
102-
# microseconds are lost during a round-trip in the database
103-
self.assertEqual(event.dt.replace(tzinfo=EAT), dt.replace(microsecond=0))
104-
10583
@skipUnlessDBFeature('supports_timezones')
10684
def test_aware_datetime_in_utc(self):
10785
dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
@@ -274,7 +252,6 @@ def test_datetime_from_date(self):
274252
self.assertEqual(event.dt, datetime.datetime(2011, 9, 1, tzinfo=EAT))
275253

276254
@requires_tz_support
277-
@skipUnlessDBFeature('supports_microsecond_precision')
278255
def test_naive_datetime_with_microsecond(self):
279256
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
280257
with warnings.catch_warnings(record=True) as recorded:
@@ -288,43 +265,18 @@ def test_naive_datetime_with_microsecond(self):
288265
# naive datetimes are interpreted in local time
289266
self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
290267

291-
@requires_tz_support
292-
@skipIfDBFeature('supports_microsecond_precision')
293-
def test_naive_datetime_with_microsecond_unsupported(self):
294-
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
295-
with warnings.catch_warnings(record=True) as recorded:
296-
warnings.simplefilter('always')
297-
Event.objects.create(dt=dt)
298-
self.assertEqual(len(recorded), 1)
299-
msg = str(recorded[0].message)
300-
self.assertTrue(msg.startswith("DateTimeField Event.dt received "
301-
"a naive datetime"))
302-
event = Event.objects.get()
303-
# microseconds are lost during a round-trip in the database
304-
# naive datetimes are interpreted in local time
305-
self.assertEqual(event.dt, dt.replace(microsecond=0, tzinfo=EAT))
306-
307268
def test_aware_datetime_in_local_timezone(self):
308269
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
309270
Event.objects.create(dt=dt)
310271
event = Event.objects.get()
311272
self.assertEqual(event.dt, dt)
312273

313-
@skipUnlessDBFeature('supports_microsecond_precision')
314274
def test_aware_datetime_in_local_timezone_with_microsecond(self):
315275
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
316276
Event.objects.create(dt=dt)
317277
event = Event.objects.get()
318278
self.assertEqual(event.dt, dt)
319279

320-
@skipIfDBFeature('supports_microsecond_precision')
321-
def test_aware_datetime_in_local_timezone_with_microsecond_unsupported(self):
322-
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
323-
Event.objects.create(dt=dt)
324-
event = Event.objects.get()
325-
# microseconds are lost during a round-trip in the database
326-
self.assertEqual(event.dt, dt.replace(microsecond=0))
327-
328280
def test_aware_datetime_in_utc(self):
329281
dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
330282
Event.objects.create(dt=dt)

0 commit comments

Comments
 (0)