Kaydet (Commit) a80903b7 authored tarafından Tim Graham's avatar Tim Graham

Removed DatabaseFeatures.supports_microsecond_precision.

MySQL 5.5 (refs #28552) was the last database to use it.
üst 8a176843
...@@ -70,9 +70,6 @@ class BaseDatabaseFeatures: ...@@ -70,9 +70,6 @@ class BaseDatabaseFeatures:
# by returning the type used to store duration field? # by returning the type used to store duration field?
supports_temporal_subtraction = False supports_temporal_subtraction = False
# Do time/datetime fields have microsecond precision?
supports_microsecond_precision = True
# Does the __regex lookup support backreferencing and grouping? # Does the __regex lookup support backreferencing and grouping?
supports_regex_backreferencing = True supports_regex_backreferencing = True
......
...@@ -6,8 +6,7 @@ from django.db import DEFAULT_DB_ALIAS, DatabaseError, connections ...@@ -6,8 +6,7 @@ from django.db import DEFAULT_DB_ALIAS, DatabaseError, connections
from django.db.models.manager import BaseManager from django.db.models.manager import BaseManager
from django.db.models.query import EmptyQuerySet, QuerySet from django.db.models.query import EmptyQuerySet, QuerySet
from django.test import ( from django.test import (
SimpleTestCase, TestCase, TransactionTestCase, skipIfDBFeature, SimpleTestCase, TestCase, TransactionTestCase, skipUnlessDBFeature,
skipUnlessDBFeature,
) )
from django.utils.translation import gettext_lazy from django.utils.translation import gettext_lazy
...@@ -164,9 +163,7 @@ class ModelTest(TestCase): ...@@ -164,9 +163,7 @@ class ModelTest(TestCase):
self.assertNotEqual(Article.objects.get(id__exact=a1.id), Article.objects.get(id__exact=a2.id)) self.assertNotEqual(Article.objects.get(id__exact=a1.id), Article.objects.get(id__exact=a2.id))
@skipUnlessDBFeature('supports_microsecond_precision')
def test_microsecond_precision(self): def test_microsecond_precision(self):
# In PostgreSQL, microsecond-level precision is available.
a9 = Article( a9 = Article(
headline='Article 9', headline='Article 9',
pub_date=datetime(2005, 7, 31, 12, 30, 45, 180), pub_date=datetime(2005, 7, 31, 12, 30, 45, 180),
...@@ -174,33 +171,6 @@ class ModelTest(TestCase): ...@@ -174,33 +171,6 @@ class ModelTest(TestCase):
a9.save() a9.save()
self.assertEqual(Article.objects.get(pk=a9.pk).pub_date, datetime(2005, 7, 31, 12, 30, 45, 180)) self.assertEqual(Article.objects.get(pk=a9.pk).pub_date, datetime(2005, 7, 31, 12, 30, 45, 180))
@skipIfDBFeature('supports_microsecond_precision')
def test_microsecond_precision_not_supported(self):
# In MySQL, microsecond-level precision isn't always available. You'll
# lose microsecond-level precision once the data is saved.
a9 = Article(
headline='Article 9',
pub_date=datetime(2005, 7, 31, 12, 30, 45, 180),
)
a9.save()
self.assertEqual(
Article.objects.get(id__exact=a9.id).pub_date,
datetime(2005, 7, 31, 12, 30, 45),
)
@skipIfDBFeature('supports_microsecond_precision')
def test_microsecond_precision_not_supported_edge_case(self):
# In MySQL, microsecond-level precision isn't always available. You'll
# lose microsecond-level precision once the data is saved.
a = Article.objects.create(
headline='Article',
pub_date=datetime(2008, 12, 31, 23, 59, 59, 999999),
)
self.assertEqual(
Article.objects.get(pk=a.pk).pub_date,
datetime(2008, 12, 31, 23, 59, 59),
)
def test_manually_specify_primary_key(self): def test_manually_specify_primary_key(self):
# You can manually specify the primary key when creating a new object. # You can manually specify the primary key when creating a new object.
a101 = Article( a101 = Article(
...@@ -667,14 +637,10 @@ class SelectOnSaveTests(TestCase): ...@@ -667,14 +637,10 @@ class SelectOnSaveTests(TestCase):
class ModelRefreshTests(TestCase): class ModelRefreshTests(TestCase):
def _truncate_ms(self, val):
# MySQL < 5.6.4 removes microseconds from the datetimes which can cause
# problems when comparing the original value to that loaded from DB
return val - timedelta(microseconds=val.microsecond)
def test_refresh(self): def test_refresh(self):
a = Article.objects.create(pub_date=self._truncate_ms(datetime.now())) a = Article.objects.create(pub_date=datetime.now())
Article.objects.create(pub_date=self._truncate_ms(datetime.now())) Article.objects.create(pub_date=datetime.now())
Article.objects.filter(pk=a.pk).update(headline='new headline') Article.objects.filter(pk=a.pk).update(headline='new headline')
with self.assertNumQueries(1): with self.assertNumQueries(1):
a.refresh_from_db() a.refresh_from_db()
...@@ -722,7 +688,7 @@ class ModelRefreshTests(TestCase): ...@@ -722,7 +688,7 @@ class ModelRefreshTests(TestCase):
self.assertEqual(s2.selfref, s1) self.assertEqual(s2.selfref, s1)
def test_refresh_unsaved(self): def test_refresh_unsaved(self):
pub_date = self._truncate_ms(datetime.now()) pub_date = datetime.now()
a = Article.objects.create(pub_date=pub_date) a = Article.objects.create(pub_date=pub_date)
a2 = Article(id=a.pk) a2 = Article(id=a.pk)
with self.assertNumQueries(1): with self.assertNumQueries(1):
...@@ -742,6 +708,6 @@ class ModelRefreshTests(TestCase): ...@@ -742,6 +708,6 @@ class ModelRefreshTests(TestCase):
self.assertIsNone(s1.article) self.assertIsNone(s1.article)
def test_refresh_no_fields(self): def test_refresh_no_fields(self):
a = Article.objects.create(pub_date=self._truncate_ms(datetime.now())) a = Article.objects.create(pub_date=datetime.now())
with self.assertNumQueries(0): with self.assertNumQueries(0):
a.refresh_from_db(fields=[]) a.refresh_from_db(fields=[])
...@@ -20,10 +20,6 @@ lorem_ipsum = """ ...@@ -20,10 +20,6 @@ lorem_ipsum = """
tempor incididunt ut labore et dolore magna aliqua.""" tempor incididunt ut labore et dolore magna aliqua."""
def truncate_microseconds(value):
return value if connection.features.supports_microsecond_precision else value.replace(microsecond=0)
class FunctionTests(TestCase): class FunctionTests(TestCase):
def test_coalesce(self): def test_coalesce(self):
...@@ -121,7 +117,7 @@ class FunctionTests(TestCase): ...@@ -121,7 +117,7 @@ class FunctionTests(TestCase):
articles = Article.objects.annotate( articles = Article.objects.annotate(
last_updated=Greatest('written', 'published'), last_updated=Greatest('written', 'published'),
) )
self.assertEqual(articles.first().last_updated, truncate_microseconds(now)) self.assertEqual(articles.first().last_updated, now)
@skipUnlessDBFeature('greatest_least_ignores_nulls') @skipUnlessDBFeature('greatest_least_ignores_nulls')
def test_greatest_ignores_null(self): def test_greatest_ignores_null(self):
...@@ -174,7 +170,7 @@ class FunctionTests(TestCase): ...@@ -174,7 +170,7 @@ class FunctionTests(TestCase):
Coalesce('published', past_sql), Coalesce('published', past_sql),
), ),
) )
self.assertEqual(articles.first().last_updated, truncate_microseconds(now)) self.assertEqual(articles.first().last_updated, now)
def test_greatest_all_null(self): def test_greatest_all_null(self):
Article.objects.create(title="Testing with Django", written=timezone.now()) Article.objects.create(title="Testing with Django", written=timezone.now())
...@@ -225,7 +221,7 @@ class FunctionTests(TestCase): ...@@ -225,7 +221,7 @@ class FunctionTests(TestCase):
articles = Article.objects.annotate( articles = Article.objects.annotate(
first_updated=Least('written', 'published'), first_updated=Least('written', 'published'),
) )
self.assertEqual(articles.first().first_updated, truncate_microseconds(before)) self.assertEqual(articles.first().first_updated, before)
@skipUnlessDBFeature('greatest_least_ignores_nulls') @skipUnlessDBFeature('greatest_least_ignores_nulls')
def test_least_ignores_null(self): def test_least_ignores_null(self):
...@@ -278,7 +274,7 @@ class FunctionTests(TestCase): ...@@ -278,7 +274,7 @@ class FunctionTests(TestCase):
Coalesce('published', future_sql), Coalesce('published', future_sql),
), ),
) )
self.assertEqual(articles.first().last_updated, truncate_microseconds(now)) self.assertEqual(articles.first().last_updated, now)
def test_least_all_null(self): def test_least_all_null(self):
Article.objects.create(title="Testing with Django", written=timezone.now()) Article.objects.create(title="Testing with Django", written=timezone.now())
......
...@@ -1028,19 +1028,16 @@ class FTimeDeltaTests(TestCase): ...@@ -1028,19 +1028,16 @@ class FTimeDeltaTests(TestCase):
# e1: started one day after assigned, tiny duration, data # e1: started one day after assigned, tiny duration, data
# set so that end time has no fractional seconds, which # set so that end time has no fractional seconds, which
# tests an edge case on sqlite. This Experiment is only # tests an edge case on sqlite.
# included in the test data when the DB supports microsecond delay = datetime.timedelta(1)
# precision. end = stime + delay + delta1
if connection.features.supports_microsecond_precision: e1 = Experiment.objects.create(
delay = datetime.timedelta(1) name='e1', assigned=sday, start=stime + delay, end=end,
end = stime + delay + delta1 completed=end.date(), estimated_time=delta1,
e1 = Experiment.objects.create( )
name='e1', assigned=sday, start=stime + delay, end=end, cls.deltas.append(delta1)
completed=end.date(), estimated_time=delta1, cls.delays.append(e1.start - datetime.datetime.combine(e1.assigned, midnight))
) cls.days_long.append(e1.completed - e1.assigned)
cls.deltas.append(delta1)
cls.delays.append(e1.start - datetime.datetime.combine(e1.assigned, midnight))
cls.days_long.append(e1.completed - e1.assigned)
# e2: started three days after assigned, small duration # e2: started three days after assigned, small duration
end = stime + delta2 end = stime + delta2
...@@ -1144,8 +1141,6 @@ class FTimeDeltaTests(TestCase): ...@@ -1144,8 +1141,6 @@ class FTimeDeltaTests(TestCase):
def test_mixed_comparisons1(self): def test_mixed_comparisons1(self):
for i in range(len(self.delays)): for i in range(len(self.delays)):
delay = self.delays[i] delay = self.delays[i]
if not connection.features.supports_microsecond_precision:
delay = datetime.timedelta(delay.days, delay.seconds)
test_set = [e.name for e in Experiment.objects.filter(assigned__gt=F('start') - delay)] test_set = [e.name for e in Experiment.objects.filter(assigned__gt=F('start') - delay)]
self.assertEqual(test_set, self.expnames[:i]) self.assertEqual(test_set, self.expnames[:i])
...@@ -1213,27 +1208,21 @@ class FTimeDeltaTests(TestCase): ...@@ -1213,27 +1208,21 @@ class FTimeDeltaTests(TestCase):
self.assertEqual(at_least_120_days, {'e5'}) self.assertEqual(at_least_120_days, {'e5'})
less_than_5_days = {e.name for e in queryset.filter(completion_duration__lt=datetime.timedelta(days=5))} less_than_5_days = {e.name for e in queryset.filter(completion_duration__lt=datetime.timedelta(days=5))}
expected = {'e0', 'e2'} self.assertEqual(less_than_5_days, {'e0', 'e1', 'e2'})
if connection.features.supports_microsecond_precision:
expected.add('e1')
self.assertEqual(less_than_5_days, expected)
@skipUnlessDBFeature('supports_temporal_subtraction') @skipUnlessDBFeature('supports_temporal_subtraction')
def test_time_subtraction(self): def test_time_subtraction(self):
if connection.features.supports_microsecond_precision: Time.objects.create(time=datetime.time(12, 30, 15, 2345))
time = datetime.time(12, 30, 15, 2345)
timedelta = datetime.timedelta(hours=1, minutes=15, seconds=15, microseconds=2345)
else:
time = datetime.time(12, 30, 15)
timedelta = datetime.timedelta(hours=1, minutes=15, seconds=15)
Time.objects.create(time=time)
queryset = Time.objects.annotate( queryset = Time.objects.annotate(
difference=ExpressionWrapper( difference=ExpressionWrapper(
F('time') - Value(datetime.time(11, 15, 0), output_field=models.TimeField()), F('time') - Value(datetime.time(11, 15, 0), output_field=models.TimeField()),
output_field=models.DurationField(), output_field=models.DurationField(),
) )
) )
self.assertEqual(queryset.get().difference, timedelta) self.assertEqual(
queryset.get().difference,
datetime.timedelta(hours=1, minutes=15, seconds=15, microseconds=2345)
)
@skipUnlessDBFeature('supports_temporal_subtraction') @skipUnlessDBFeature('supports_temporal_subtraction')
def test_datetime_subtraction(self): def test_datetime_subtraction(self):
...@@ -1274,10 +1263,9 @@ class FTimeDeltaTests(TestCase): ...@@ -1274,10 +1263,9 @@ class FTimeDeltaTests(TestCase):
new_start=F('start_sub_hours') + datetime.timedelta(days=-2), new_start=F('start_sub_hours') + datetime.timedelta(days=-2),
) )
expected_start = datetime.datetime(2010, 6, 23, 9, 45, 0) expected_start = datetime.datetime(2010, 6, 23, 9, 45, 0)
if connection.features.supports_microsecond_precision: # subtract 30 microseconds
# subtract 30 microseconds experiments = experiments.annotate(new_start=F('new_start') + datetime.timedelta(microseconds=-30))
experiments = experiments.annotate(new_start=F('new_start') + datetime.timedelta(microseconds=-30)) expected_start += datetime.timedelta(microseconds=+746970)
expected_start += datetime.timedelta(microseconds=+746970)
experiments.update(start=F('new_start')) experiments.update(start=F('new_start'))
e0 = Experiment.objects.get(name='e0') e0 = Experiment.objects.get(name='e0')
self.assertEqual(e0.start, expected_start) self.assertEqual(e0.start, expected_start)
......
from datetime import datetime from datetime import datetime
from operator import attrgetter from operator import attrgetter
from django.test import TestCase, skipUnlessDBFeature from django.test import TestCase
from .models import ( from .models import (
CustomMembership, Employee, Event, Friendship, Group, Ingredient, CustomMembership, Employee, Event, Friendship, Group, Ingredient,
...@@ -196,7 +196,6 @@ class M2mThroughTests(TestCase): ...@@ -196,7 +196,6 @@ class M2mThroughTests(TestCase):
attrgetter("name") attrgetter("name")
) )
@skipUnlessDBFeature('supports_microsecond_precision')
def test_order_by_relational_field_through_model(self): def test_order_by_relational_field_through_model(self):
CustomMembership.objects.create(person=self.jim, group=self.rock) CustomMembership.objects.create(person=self.jim, group=self.rock)
CustomMembership.objects.create(person=self.bob, group=self.rock) CustomMembership.objects.create(person=self.bob, group=self.rock)
......
...@@ -24,7 +24,6 @@ class DateTimeFieldTests(TestCase): ...@@ -24,7 +24,6 @@ class DateTimeFieldTests(TestCase):
self.assertEqual(f.to_python('01:02:03.000004'), datetime.time(1, 2, 3, 4)) self.assertEqual(f.to_python('01:02:03.000004'), datetime.time(1, 2, 3, 4))
self.assertEqual(f.to_python('01:02:03.999999'), datetime.time(1, 2, 3, 999999)) self.assertEqual(f.to_python('01:02:03.999999'), datetime.time(1, 2, 3, 999999))
@skipUnlessDBFeature('supports_microsecond_precision')
def test_datetimes_save_completely(self): def test_datetimes_save_completely(self):
dat = datetime.date(2014, 3, 12) dat = datetime.date(2014, 3, 12)
datetim = datetime.datetime(2014, 3, 12, 21, 22, 23, 240000) datetim = datetime.datetime(2014, 3, 12, 21, 22, 23, 240000)
......
...@@ -56,21 +56,12 @@ class LegacyDatabaseTests(TestCase): ...@@ -56,21 +56,12 @@ class LegacyDatabaseTests(TestCase):
event = Event.objects.get() event = Event.objects.get()
self.assertEqual(event.dt, dt) self.assertEqual(event.dt, dt)
@skipUnlessDBFeature('supports_microsecond_precision')
def test_naive_datetime_with_microsecond(self): def test_naive_datetime_with_microsecond(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060) dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
Event.objects.create(dt=dt) Event.objects.create(dt=dt)
event = Event.objects.get() event = Event.objects.get()
self.assertEqual(event.dt, dt) self.assertEqual(event.dt, dt)
@skipIfDBFeature('supports_microsecond_precision')
def test_naive_datetime_with_microsecond_unsupported(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
Event.objects.create(dt=dt)
event = Event.objects.get()
# microseconds are lost during a round-trip in the database
self.assertEqual(event.dt, dt.replace(microsecond=0))
@skipUnlessDBFeature('supports_timezones') @skipUnlessDBFeature('supports_timezones')
def test_aware_datetime_in_local_timezone(self): def test_aware_datetime_in_local_timezone(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT) dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
...@@ -81,7 +72,6 @@ class LegacyDatabaseTests(TestCase): ...@@ -81,7 +72,6 @@ class LegacyDatabaseTests(TestCase):
self.assertEqual(event.dt.replace(tzinfo=EAT), dt) self.assertEqual(event.dt.replace(tzinfo=EAT), dt)
@skipUnlessDBFeature('supports_timezones') @skipUnlessDBFeature('supports_timezones')
@skipUnlessDBFeature('supports_microsecond_precision')
def test_aware_datetime_in_local_timezone_with_microsecond(self): def test_aware_datetime_in_local_timezone_with_microsecond(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT) dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
Event.objects.create(dt=dt) Event.objects.create(dt=dt)
...@@ -90,18 +80,6 @@ class LegacyDatabaseTests(TestCase): ...@@ -90,18 +80,6 @@ class LegacyDatabaseTests(TestCase):
# interpret the naive datetime in local time to get the correct value # interpret the naive datetime in local time to get the correct value
self.assertEqual(event.dt.replace(tzinfo=EAT), dt) self.assertEqual(event.dt.replace(tzinfo=EAT), dt)
# This combination actually never happens.
@skipUnlessDBFeature('supports_timezones')
@skipIfDBFeature('supports_microsecond_precision')
def test_aware_datetime_in_local_timezone_with_microsecond_unsupported(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
Event.objects.create(dt=dt)
event = Event.objects.get()
self.assertIsNone(event.dt.tzinfo)
# interpret the naive datetime in local time to get the correct value
# microseconds are lost during a round-trip in the database
self.assertEqual(event.dt.replace(tzinfo=EAT), dt.replace(microsecond=0))
@skipUnlessDBFeature('supports_timezones') @skipUnlessDBFeature('supports_timezones')
def test_aware_datetime_in_utc(self): def test_aware_datetime_in_utc(self):
dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC) dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
...@@ -274,7 +252,6 @@ class NewDatabaseTests(TestCase): ...@@ -274,7 +252,6 @@ class NewDatabaseTests(TestCase):
self.assertEqual(event.dt, datetime.datetime(2011, 9, 1, tzinfo=EAT)) self.assertEqual(event.dt, datetime.datetime(2011, 9, 1, tzinfo=EAT))
@requires_tz_support @requires_tz_support
@skipUnlessDBFeature('supports_microsecond_precision')
def test_naive_datetime_with_microsecond(self): def test_naive_datetime_with_microsecond(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060) dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
with warnings.catch_warnings(record=True) as recorded: with warnings.catch_warnings(record=True) as recorded:
...@@ -288,43 +265,18 @@ class NewDatabaseTests(TestCase): ...@@ -288,43 +265,18 @@ class NewDatabaseTests(TestCase):
# naive datetimes are interpreted in local time # naive datetimes are interpreted in local time
self.assertEqual(event.dt, dt.replace(tzinfo=EAT)) self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
@requires_tz_support
@skipIfDBFeature('supports_microsecond_precision')
def test_naive_datetime_with_microsecond_unsupported(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
Event.objects.create(dt=dt)
self.assertEqual(len(recorded), 1)
msg = str(recorded[0].message)
self.assertTrue(msg.startswith("DateTimeField Event.dt received "
"a naive datetime"))
event = Event.objects.get()
# microseconds are lost during a round-trip in the database
# naive datetimes are interpreted in local time
self.assertEqual(event.dt, dt.replace(microsecond=0, tzinfo=EAT))
def test_aware_datetime_in_local_timezone(self): def test_aware_datetime_in_local_timezone(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT) dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
Event.objects.create(dt=dt) Event.objects.create(dt=dt)
event = Event.objects.get() event = Event.objects.get()
self.assertEqual(event.dt, dt) self.assertEqual(event.dt, dt)
@skipUnlessDBFeature('supports_microsecond_precision')
def test_aware_datetime_in_local_timezone_with_microsecond(self): def test_aware_datetime_in_local_timezone_with_microsecond(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT) dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
Event.objects.create(dt=dt) Event.objects.create(dt=dt)
event = Event.objects.get() event = Event.objects.get()
self.assertEqual(event.dt, dt) self.assertEqual(event.dt, dt)
@skipIfDBFeature('supports_microsecond_precision')
def test_aware_datetime_in_local_timezone_with_microsecond_unsupported(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
Event.objects.create(dt=dt)
event = Event.objects.get()
# microseconds are lost during a round-trip in the database
self.assertEqual(event.dt, dt.replace(microsecond=0))
def test_aware_datetime_in_utc(self): def test_aware_datetime_in_utc(self):
dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC) dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
Event.objects.create(dt=dt) Event.objects.create(dt=dt)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment