summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2016-06-18 23:39:26 -0400
committerSimon Charette <charette.s@gmail.com>2016-07-08 12:35:34 -0400
commit8a4f017f4565c51c83aabb61a816e334e8638432 (patch)
treefa6f6a4fcaf158dd161ef85fa85c3072390626e6 /django
parent082c52dbedd76c312cebf3b23e04c449a94c20b6 (diff)
Fixed #26348 -- Added TruncTime and exposed it through the __time lookup.
Thanks Tim for the review.
Diffstat (limited to 'django')
-rw-r--r--django/db/backends/base/operations.py6
-rw-r--r--django/db/backends/mysql/operations.py5
-rw-r--r--django/db/backends/oracle/operations.py6
-rw-r--r--django/db/backends/postgresql/operations.py5
-rw-r--r--django/db/backends/sqlite3/base.py8
-rw-r--r--django/db/backends/sqlite3/operations.py4
-rw-r--r--django/db/models/functions/__init__.py4
-rw-r--r--django/db/models/functions/datetime.py18
8 files changed, 54 insertions, 2 deletions
diff --git a/django/db/backends/base/operations.py b/django/db/backends/base/operations.py
index 63081ba113..bf9af0149a 100644
--- a/django/db/backends/base/operations.py
+++ b/django/db/backends/base/operations.py
@@ -96,6 +96,12 @@ class BaseDatabaseOperations(object):
"""
raise NotImplementedError('subclasses of BaseDatabaseOperations may require a datetime_cast_date() method')
+ def datetime_cast_time_sql(self, field_name, tzname):
+ """
+ Returns the SQL necessary to cast a datetime value to time value.
+ """
+ raise NotImplementedError('subclasses of BaseDatabaseOperations may require a datetime_cast_time_sql() method')
+
def datetime_extract_sql(self, lookup_type, field_name, tzname):
"""
Given a lookup_type of 'year', 'month', 'day', 'hour', 'minute' or
diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py
index 5ced46f970..f0fd8314ae 100644
--- a/django/db/backends/mysql/operations.py
+++ b/django/db/backends/mysql/operations.py
@@ -51,6 +51,11 @@ class DatabaseOperations(BaseDatabaseOperations):
sql = "DATE(%s)" % field_name
return sql, params
+ def datetime_cast_time_sql(self, field_name, tzname):
+ field_name, params = self._convert_field_to_tz(field_name, tzname)
+ sql = "TIME(%s)" % field_name
+ return sql, params
+
def datetime_extract_sql(self, lookup_type, field_name, tzname):
field_name, params = self._convert_field_to_tz(field_name, tzname)
sql = self.date_extract_sql(lookup_type, field_name)
diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py
index 0a6a239956..3761ed0df1 100644
--- a/django/db/backends/oracle/operations.py
+++ b/django/db/backends/oracle/operations.py
@@ -128,6 +128,12 @@ WHEN (new.%(col_name)s IS NULL)
sql = 'TRUNC(%s)' % field_name
return sql, []
+ def datetime_cast_time_sql(self, field_name, tzname):
+ # Since `TimeField` values are stored as TIMESTAMP where only the date
+ # part is ignored, convert the field to the specified timezone.
+ field_name = self._convert_field_to_tz(field_name, tzname)
+ return field_name, []
+
def datetime_extract_sql(self, lookup_type, field_name, tzname):
field_name = self._convert_field_to_tz(field_name, tzname)
sql = self.date_extract_sql(lookup_type, field_name)
diff --git a/django/db/backends/postgresql/operations.py b/django/db/backends/postgresql/operations.py
index 2130571a05..c32ca040e7 100644
--- a/django/db/backends/postgresql/operations.py
+++ b/django/db/backends/postgresql/operations.py
@@ -45,6 +45,11 @@ class DatabaseOperations(BaseDatabaseOperations):
sql = '(%s)::date' % field_name
return sql, params
+ def datetime_cast_time_sql(self, field_name, tzname):
+ field_name, params = self._convert_field_to_tz(field_name, tzname)
+ sql = '(%s)::time' % field_name
+ return sql, params
+
def datetime_extract_sql(self, lookup_type, field_name, tzname):
field_name, params = self._convert_field_to_tz(field_name, tzname)
sql = self.date_extract_sql(lookup_type, field_name)
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
index 70d511f108..870dc10353 100644
--- a/django/db/backends/sqlite3/base.py
+++ b/django/db/backends/sqlite3/base.py
@@ -210,6 +210,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
conn.create_function("django_date_extract", 2, _sqlite_date_extract)
conn.create_function("django_date_trunc", 2, _sqlite_date_trunc)
conn.create_function("django_datetime_cast_date", 2, _sqlite_datetime_cast_date)
+ conn.create_function("django_datetime_cast_time", 2, _sqlite_datetime_cast_time)
conn.create_function("django_datetime_extract", 3, _sqlite_datetime_extract)
conn.create_function("django_datetime_trunc", 3, _sqlite_datetime_trunc)
conn.create_function("django_time_extract", 2, _sqlite_time_extract)
@@ -403,6 +404,13 @@ def _sqlite_datetime_cast_date(dt, tzname):
return dt.date().isoformat()
+def _sqlite_datetime_cast_time(dt, tzname):
+ dt = _sqlite_datetime_parse(dt, tzname)
+ if dt is None:
+ return None
+ return dt.time().isoformat()
+
+
def _sqlite_datetime_extract(lookup_type, dt, tzname):
dt = _sqlite_datetime_parse(dt, tzname)
if dt is None:
diff --git a/django/db/backends/sqlite3/operations.py b/django/db/backends/sqlite3/operations.py
index 4b7fc091db..bf3002b79b 100644
--- a/django/db/backends/sqlite3/operations.py
+++ b/django/db/backends/sqlite3/operations.py
@@ -85,6 +85,10 @@ class DatabaseOperations(BaseDatabaseOperations):
self._require_pytz()
return "django_datetime_cast_date(%s, %%s)" % field_name, [tzname]
+ def datetime_cast_time_sql(self, field_name, tzname):
+ self._require_pytz()
+ return "django_datetime_cast_time(%s, %%s)" % field_name, [tzname]
+
def datetime_extract_sql(self, lookup_type, field_name, tzname):
# Same comment as in date_extract_sql.
self._require_pytz()
diff --git a/django/db/models/functions/__init__.py b/django/db/models/functions/__init__.py
index 14f1f69d01..dd45d7bb4c 100644
--- a/django/db/models/functions/__init__.py
+++ b/django/db/models/functions/__init__.py
@@ -5,7 +5,7 @@ from .base import (
from .datetime import (
Extract, ExtractDay, ExtractHour, ExtractMinute, ExtractMonth,
ExtractSecond, ExtractWeekDay, ExtractYear, Trunc, TruncDate, TruncDay,
- TruncHour, TruncMinute, TruncMonth, TruncSecond, TruncYear,
+ TruncHour, TruncMinute, TruncMonth, TruncSecond, TruncTime, TruncYear,
)
__all__ = [
@@ -16,5 +16,5 @@ __all__ = [
'Extract', 'ExtractDay', 'ExtractHour', 'ExtractMinute', 'ExtractMonth',
'ExtractSecond', 'ExtractWeekDay', 'ExtractYear',
'Trunc', 'TruncDate', 'TruncDay', 'TruncHour', 'TruncMinute', 'TruncMonth',
- 'TruncSecond', 'TruncYear',
+ 'TruncSecond', 'TruncTime', 'TruncYear',
]
diff --git a/django/db/models/functions/datetime.py b/django/db/models/functions/datetime.py
index 85a398a50b..9cbdcb0231 100644
--- a/django/db/models/functions/datetime.py
+++ b/django/db/models/functions/datetime.py
@@ -239,6 +239,23 @@ class TruncDate(TruncBase):
return sql, lhs_params
+class TruncTime(TruncBase):
+ kind = 'time'
+ lookup_name = 'time'
+
+ @cached_property
+ def output_field(self):
+ return TimeField()
+
+ def as_sql(self, compiler, connection):
+ # Cast to date rather than truncate to date.
+ lhs, lhs_params = compiler.compile(self.lhs)
+ tzname = timezone.get_current_timezone_name() if settings.USE_TZ else None
+ sql, tz_params = connection.ops.datetime_cast_time_sql(lhs, tzname)
+ lhs_params.extend(tz_params)
+ return sql, lhs_params
+
+
class TruncHour(TruncBase):
kind = 'hour'
@@ -252,3 +269,4 @@ class TruncSecond(TruncBase):
DateTimeField.register_lookup(TruncDate)
+DateTimeField.register_lookup(TruncTime)