From 8d8da826dbf1a702f8b11c3942bf8134c4f0f165 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Thu, 11 Aug 2005 19:34:34 +0000 Subject: [PATCH] Changed timestamp and time typecasting to preserve microseconds. Added unit tests to test this behavior, and added a db_typecast unit test module. Refs #306. git-svn-id: http://code.djangoproject.com/svn/django/trunk@487 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/core/db/typecasts.py | 7 +++-- django/core/meta/fields.py | 4 +-- tests/othertests/db_typecasts.py | 51 ++++++++++++++++++++++++++++++++ tests/testapp/models/basic.py | 35 ++++++++++++++++++++++ 4 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 tests/othertests/db_typecasts.py diff --git a/django/core/db/typecasts.py b/django/core/db/typecasts.py index 9f73ec87a2..e78eab0180 100644 --- a/django/core/db/typecasts.py +++ b/django/core/db/typecasts.py @@ -5,7 +5,7 @@ import datetime ############################################### def typecast_date(s): - return s and datetime.date(*map(int, s.split('-'))) # returns None if s is null + return s and datetime.date(*map(int, s.split('-'))) or None # returns None if s is null def typecast_time(s): # does NOT store time zone information if not s: return None @@ -14,7 +14,7 @@ def typecast_time(s): # does NOT store time zone information seconds, microseconds = seconds.split('.') else: microseconds = '0' - return datetime.time(int(hour), int(minutes), int(seconds), int(microseconds)) + return datetime.time(int(hour), int(minutes), int(seconds), int(float('.'+microseconds) * 1000000)) def typecast_timestamp(s): # does NOT store time zone information # "2005-07-29 15:48:00.590358-05" @@ -39,10 +39,11 @@ def typecast_timestamp(s): # does NOT store time zone information else: microseconds = '0' return datetime.datetime(int(dates[0]), int(dates[1]), int(dates[2]), - int(times[0]), int(times[1]), int(seconds), int(microseconds)) + int(times[0]), int(times[1]), int(seconds), int(float('.'+microseconds) * 1000000)) def typecast_boolean(s): if s is None: return None + if not s: return False return str(s)[0].lower() == 't' ############################################### diff --git a/django/core/meta/fields.py b/django/core/meta/fields.py index adbfe4ca92..6743ed79a9 100644 --- a/django/core/meta/fields.py +++ b/django/core/meta/fields.py @@ -299,7 +299,7 @@ class DateTimeField(DateField): def get_db_prep_save(self, value): # Casts dates into string format for entry into database. if value is not None: - value = value.strftime('%Y-%m-%d %H:%M:%S') + value = str(value) return Field.get_db_prep_save(self, value) def get_manipulator_field_objs(self): @@ -493,7 +493,7 @@ class TimeField(Field): def get_db_prep_save(self, value): # Casts dates into string format for entry into database. if value is not None: - value = value.strftime('%H:%M:%S') + value = str(value) return Field.get_db_prep_save(self, value) def get_manipulator_field_objs(self): diff --git a/tests/othertests/db_typecasts.py b/tests/othertests/db_typecasts.py new file mode 100644 index 0000000000..52cab666de --- /dev/null +++ b/tests/othertests/db_typecasts.py @@ -0,0 +1,51 @@ +# Unit tests for django.core.db.typecasts + +from django.core.db import typecasts +import datetime + +TEST_CASES = { + 'typecast_date': ( + ('', None), + (None, None), + ('2005-08-11', datetime.date(2005, 8, 11)), + ('1990-01-01', datetime.date(1990, 1, 1)), + ), + 'typecast_time': ( + ('', None), + (None, None), + ('0:00:00', datetime.time(0, 0)), + ('0:30:00', datetime.time(0, 30)), + ('8:50:00', datetime.time(8, 50)), + ('08:50:00', datetime.time(8, 50)), + ('12:00:00', datetime.time(12, 00)), + ('12:30:00', datetime.time(12, 30)), + ('13:00:00', datetime.time(13, 00)), + ('23:59:00', datetime.time(23, 59)), + ('00:00:12', datetime.time(0, 0, 12)), + ('00:00:12.5', datetime.time(0, 0, 12, 500000)), + ('7:22:13.312', datetime.time(7, 22, 13, 312000)), + ), + 'typecast_timestamp': ( + ('', None), + (None, None), + ('2005-08-11 0:00:00', datetime.datetime(2005, 8, 11)), + ('2005-08-11 0:30:00', datetime.datetime(2005, 8, 11, 0, 30)), + ('2005-08-11 8:50:30', datetime.datetime(2005, 8, 11, 8, 50, 30)), + ('2005-08-11 8:50:30.123', datetime.datetime(2005, 8, 11, 8, 50, 30, 123000)), + ('2005-08-11 8:50:30.9', datetime.datetime(2005, 8, 11, 8, 50, 30, 900000)), + ('2005-08-11 8:50:30.312-05', datetime.datetime(2005, 8, 11, 8, 50, 30, 312000)), + ('2005-08-11 8:50:30.312+02', datetime.datetime(2005, 8, 11, 8, 50, 30, 312000)), + ), + 'typecast_boolean': ( + (None, None), + ('', False), + ('t', True), + ('f', False), + ('x', False), + ), +} + +for k, v in TEST_CASES.items(): + for inpt, expected in v: + got = getattr(typecasts, k)(inpt) + assert got == expected, "In %s: %r doesn't match %r. Got %r instead." % (k, inpt, expected, got) diff --git a/tests/testapp/models/basic.py b/tests/testapp/models/basic.py index 86b08122c3..3668820c94 100644 --- a/tests/testapp/models/basic.py +++ b/tests/testapp/models/basic.py @@ -120,4 +120,39 @@ TypeError: 'foo' is an invalid keyword argument for this function >>> a6.save() >>> a6.headline 'Default headline' + +# For DateTimeFields, Django saves as much precision (in seconds) as you +# give it. +>>> a7 = articles.Article(headline='Article 7', pub_date=datetime(2005, 7, 31, 12, 30)) +>>> a7.save() +>>> articles.get_object(id__exact=7).pub_date +datetime.datetime(2005, 7, 31, 12, 30) + +>>> a8 = articles.Article(headline='Article 8', pub_date=datetime(2005, 7, 31, 12, 30, 45)) +>>> a8.save() +>>> articles.get_object(id__exact=8).pub_date +datetime.datetime(2005, 7, 31, 12, 30, 45) +""" + +from django.conf import settings + +building_docs = getattr(settings, 'BUILDING_DOCS', False) + +if building_docs or settings.DATABASE_ENGINE == 'postgresql': + API_TESTS += """ +# In PostgreSQL, microsecond-level precision is available. +>>> a9 = articles.Article(headline='Article 9', pub_date=datetime(2005, 7, 31, 12, 30, 45, 180)) +>>> a9.save() +>>> articles.get_object(id__exact=9).pub_date +datetime.datetime(2005, 7, 31, 12, 30, 45, 180) +""" + +if building_docs or settings.DATABASE_ENGINE == 'mysql': + API_TESTS += """ +# In MySQL, microsecond-level precision isn't available. You'll lose +# microsecond-level precision once the data is saved. +>>> a9 = articles.Article(headline='Article 9', pub_date=datetime(2005, 7, 31, 12, 30, 45, 180)) +>>> a9.save() +>>> articles.get_object(id__exact=9).pub_date +datetime.datetime(2005, 7, 31, 12, 30, 45) """