Kaydet (Commit) 3e09b37f authored tarafından Sigurd Ljødal's avatar Sigurd Ljødal Kaydeden (comit) Tim Graham

Fixed #28649 -- Added ExtractIsoYear database function and iso_year lookup.

üst c832885a
...@@ -42,6 +42,10 @@ class DatabaseOperations(BaseDatabaseOperations): ...@@ -42,6 +42,10 @@ class DatabaseOperations(BaseDatabaseOperations):
# other database backends. # other database backends.
# Mode 3: Monday, 1-53, with 4 or more days this year. # Mode 3: Monday, 1-53, with 4 or more days this year.
return "WEEK(%s, 3)" % field_name return "WEEK(%s, 3)" % field_name
elif lookup_type == 'iso_year':
# Get the year part from the YEARWEEK function, which returns a
# number as year * 100 + week.
return "TRUNCATE(YEARWEEK(%s, 3), -2) / 100" % field_name
else: else:
# EXTRACT returns 1-53 based on ISO-8601 for the week number. # EXTRACT returns 1-53 based on ISO-8601 for the week number.
return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name) return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name)
......
...@@ -69,6 +69,8 @@ END; ...@@ -69,6 +69,8 @@ END;
return "TO_CHAR(%s, 'IW')" % field_name return "TO_CHAR(%s, 'IW')" % field_name
elif lookup_type == 'quarter': elif lookup_type == 'quarter':
return "TO_CHAR(%s, 'Q')" % field_name return "TO_CHAR(%s, 'Q')" % field_name
elif lookup_type == 'iso_year':
return "TO_CHAR(%s, 'IYYY')" % field_name
else: else:
# https://docs.oracle.com/database/121/SQLRF/functions067.htm#SQLRF00639 # https://docs.oracle.com/database/121/SQLRF/functions067.htm#SQLRF00639
return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name) return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name)
......
...@@ -31,6 +31,8 @@ class DatabaseOperations(BaseDatabaseOperations): ...@@ -31,6 +31,8 @@ class DatabaseOperations(BaseDatabaseOperations):
if lookup_type == 'week_day': if lookup_type == 'week_day':
# For consistency across backends, we return Sunday=1, Saturday=7. # For consistency across backends, we return Sunday=1, Saturday=7.
return "EXTRACT('dow' FROM %s) + 1" % field_name return "EXTRACT('dow' FROM %s) + 1" % field_name
elif lookup_type == 'iso_year':
return "EXTRACT('isoyear' FROM %s)" % field_name
else: else:
return "EXTRACT('%s' FROM %s)" % (lookup_type, field_name) return "EXTRACT('%s' FROM %s)" % (lookup_type, field_name)
......
...@@ -338,6 +338,8 @@ def _sqlite_date_extract(lookup_type, dt): ...@@ -338,6 +338,8 @@ def _sqlite_date_extract(lookup_type, dt):
return dt.isocalendar()[1] return dt.isocalendar()[1]
elif lookup_type == 'quarter': elif lookup_type == 'quarter':
return math.ceil(dt.month / 3) return math.ceil(dt.month / 3)
elif lookup_type == 'iso_year':
return dt.isocalendar()[0]
else: else:
return getattr(dt, lookup_type) return getattr(dt, lookup_type)
...@@ -410,6 +412,8 @@ def _sqlite_datetime_extract(lookup_type, dt, tzname): ...@@ -410,6 +412,8 @@ def _sqlite_datetime_extract(lookup_type, dt, tzname):
return dt.isocalendar()[1] return dt.isocalendar()[1]
elif lookup_type == 'quarter': elif lookup_type == 'quarter':
return math.ceil(dt.month / 3) return math.ceil(dt.month / 3)
elif lookup_type == 'iso_year':
return dt.isocalendar()[0]
else: else:
return getattr(dt, lookup_type) return getattr(dt, lookup_type)
......
from .comparison import Cast, Coalesce, Greatest, Least from .comparison import Cast, Coalesce, Greatest, Least
from .datetime import ( from .datetime import (
Extract, ExtractDay, ExtractHour, ExtractMinute, ExtractMonth, Extract, ExtractDay, ExtractHour, ExtractIsoYear, ExtractMinute,
ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay, ExtractYear, ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay,
Now, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute, TruncMonth, ExtractYear, Now, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute,
TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear, TruncMonth, TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear,
) )
from .math import ( from .math import (
Abs, ACos, ASin, ATan, ATan2, Ceil, Cos, Cot, Degrees, Exp, Floor, Ln, Log, Abs, ACos, ASin, ATan, ATan2, Ceil, Cos, Cot, Degrees, Exp, Floor, Ln, Log,
...@@ -24,7 +24,8 @@ __all__ = [ ...@@ -24,7 +24,8 @@ __all__ = [
# datetime # datetime
'Extract', 'ExtractDay', 'ExtractHour', 'ExtractMinute', 'ExtractMonth', 'Extract', 'ExtractDay', 'ExtractHour', 'ExtractMinute', 'ExtractMonth',
'ExtractQuarter', 'ExtractSecond', 'ExtractWeek', 'ExtractWeekDay', 'ExtractQuarter', 'ExtractSecond', 'ExtractWeek', 'ExtractWeekDay',
'ExtractYear', 'Now', 'Trunc', 'TruncDate', 'TruncDay', 'TruncHour', 'ExtractIsoYear', 'ExtractYear', 'Now', 'Trunc', 'TruncDate', 'TruncDay',
'TruncHour', 'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond',
'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncTime', 'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncTime',
'TruncWeek', 'TruncYear', 'TruncWeek', 'TruncYear',
# math # math
......
...@@ -80,6 +80,11 @@ class ExtractYear(Extract): ...@@ -80,6 +80,11 @@ class ExtractYear(Extract):
lookup_name = 'year' lookup_name = 'year'
class ExtractIsoYear(Extract):
"""Return the ISO-8601 week-numbering year."""
lookup_name = 'iso_year'
class ExtractMonth(Extract): class ExtractMonth(Extract):
lookup_name = 'month' lookup_name = 'month'
...@@ -126,6 +131,7 @@ DateField.register_lookup(ExtractMonth) ...@@ -126,6 +131,7 @@ DateField.register_lookup(ExtractMonth)
DateField.register_lookup(ExtractDay) DateField.register_lookup(ExtractDay)
DateField.register_lookup(ExtractWeekDay) DateField.register_lookup(ExtractWeekDay)
DateField.register_lookup(ExtractWeek) DateField.register_lookup(ExtractWeek)
DateField.register_lookup(ExtractIsoYear)
DateField.register_lookup(ExtractQuarter) DateField.register_lookup(ExtractQuarter)
TimeField.register_lookup(ExtractHour) TimeField.register_lookup(ExtractHour)
...@@ -142,6 +148,12 @@ ExtractYear.register_lookup(YearGte) ...@@ -142,6 +148,12 @@ ExtractYear.register_lookup(YearGte)
ExtractYear.register_lookup(YearLt) ExtractYear.register_lookup(YearLt)
ExtractYear.register_lookup(YearLte) ExtractYear.register_lookup(YearLte)
ExtractIsoYear.register_lookup(YearExact)
ExtractIsoYear.register_lookup(YearGt)
ExtractIsoYear.register_lookup(YearGte)
ExtractIsoYear.register_lookup(YearLt)
ExtractIsoYear.register_lookup(YearLte)
class Now(Func): class Now(Func):
template = 'CURRENT_TIMESTAMP' template = 'CURRENT_TIMESTAMP'
......
...@@ -182,6 +182,7 @@ Given the datetime ``2015-06-15 23:30:01.000321+00:00``, the built-in ...@@ -182,6 +182,7 @@ Given the datetime ``2015-06-15 23:30:01.000321+00:00``, the built-in
``lookup_name``\s return: ``lookup_name``\s return:
* "year": 2015 * "year": 2015
* "iso_year": 2015
* "quarter": 2 * "quarter": 2
* "month": 6 * "month": 6
* "day": 15 * "day": 15
...@@ -252,6 +253,14 @@ Usage example:: ...@@ -252,6 +253,14 @@ Usage example::
.. attribute:: lookup_name = 'year' .. attribute:: lookup_name = 'year'
.. class:: ExtractIsoYear(expression, tzinfo=None, **extra)
.. versionadded:: 2.2
Returns the ISO-8601 week-numbering year.
.. attribute:: lookup_name = 'iso_year'
.. class:: ExtractMonth(expression, tzinfo=None, **extra) .. class:: ExtractMonth(expression, tzinfo=None, **extra)
.. attribute:: lookup_name = 'month' .. attribute:: lookup_name = 'month'
...@@ -283,7 +292,7 @@ that deal with date-parts can be used with ``DateField``:: ...@@ -283,7 +292,7 @@ that deal with date-parts can be used with ``DateField``::
>>> from django.utils import timezone >>> from django.utils import timezone
>>> from django.db.models.functions import ( >>> from django.db.models.functions import (
... ExtractDay, ExtractMonth, ExtractQuarter, ExtractWeek, ... ExtractDay, ExtractMonth, ExtractQuarter, ExtractWeek,
... ExtractWeekDay, ExtractYear, ... ExtractWeekDay, ExtractIsoYear, ExtractYear,
... ) ... )
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc) >>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc) >>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
...@@ -292,15 +301,17 @@ that deal with date-parts can be used with ``DateField``:: ...@@ -292,15 +301,17 @@ that deal with date-parts can be used with ``DateField``::
... end_datetime=end_2015, end_date=end_2015.date()) ... end_datetime=end_2015, end_date=end_2015.date())
>>> Experiment.objects.annotate( >>> Experiment.objects.annotate(
... year=ExtractYear('start_date'), ... year=ExtractYear('start_date'),
... isoyear=ExtractIsoYear('start_date'),
... quarter=ExtractQuarter('start_date'), ... quarter=ExtractQuarter('start_date'),
... month=ExtractMonth('start_date'), ... month=ExtractMonth('start_date'),
... week=ExtractWeek('start_date'), ... week=ExtractWeek('start_date'),
... day=ExtractDay('start_date'), ... day=ExtractDay('start_date'),
... weekday=ExtractWeekDay('start_date'), ... weekday=ExtractWeekDay('start_date'),
... ).values('year', 'quarter', 'month', 'week', 'day', 'weekday').get( ... ).values('year', 'isoyear', 'quarter', 'month', 'week', 'day', 'weekday').get(
... end_date__year=ExtractYear('start_date'), ... end_date__year=ExtractYear('start_date'),
... ) ... )
{'year': 2015, 'quarter': 2, 'month': 6, 'week': 25, 'day': 15, 'weekday': 2} {'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25,
'day': 15, 'weekday': 2}
``DateTimeField`` extracts ``DateTimeField`` extracts
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
...@@ -340,6 +351,7 @@ Each class is also a ``Transform`` registered on ``DateTimeField`` as ...@@ -340,6 +351,7 @@ Each class is also a ``Transform`` registered on ``DateTimeField`` as
... end_datetime=end_2015, end_date=end_2015.date()) ... end_datetime=end_2015, end_date=end_2015.date())
>>> Experiment.objects.annotate( >>> Experiment.objects.annotate(
... year=ExtractYear('start_datetime'), ... year=ExtractYear('start_datetime'),
... isoyear=ExtractIsoYear('start_datetime'),
... quarter=ExtractQuarter('start_datetime'), ... quarter=ExtractQuarter('start_datetime'),
... month=ExtractMonth('start_datetime'), ... month=ExtractMonth('start_datetime'),
... week=ExtractWeek('start_datetime'), ... week=ExtractWeek('start_datetime'),
...@@ -349,10 +361,11 @@ Each class is also a ``Transform`` registered on ``DateTimeField`` as ...@@ -349,10 +361,11 @@ Each class is also a ``Transform`` registered on ``DateTimeField`` as
... minute=ExtractMinute('start_datetime'), ... minute=ExtractMinute('start_datetime'),
... second=ExtractSecond('start_datetime'), ... second=ExtractSecond('start_datetime'),
... ).values( ... ).values(
... 'year', 'month', 'week', 'day', 'weekday', 'hour', 'minute', 'second', ... 'year', 'isoyear', 'month', 'week', 'day',
... 'weekday', 'hour', 'minute', 'second',
... ).get(end_datetime__year=ExtractYear('start_datetime')) ... ).get(end_datetime__year=ExtractYear('start_datetime'))
{'year': 2015, 'quarter': 2, 'month': 6, 'week': 25, 'day': 15, 'weekday': 2, {'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25,
'hour': 23, 'minute': 30, 'second': 1} 'day': 15, 'weekday': 2, 'hour': 23, 'minute': 30, 'second': 1}
When :setting:`USE_TZ` is ``True`` then datetimes are stored in the database When :setting:`USE_TZ` is ``True`` then datetimes are stored in the database
in UTC. If a different timezone is active in Django, the datetime is converted in UTC. If a different timezone is active in Django, the datetime is converted
......
...@@ -2927,6 +2927,26 @@ SQL equivalent:: ...@@ -2927,6 +2927,26 @@ SQL equivalent::
When :setting:`USE_TZ` is ``True``, datetime fields are converted to the When :setting:`USE_TZ` is ``True``, datetime fields are converted to the
current time zone before filtering. current time zone before filtering.
.. fieldlookup:: iso_year
``iso_year``
~~~~~~~~~~~~
.. versionadded:: 2.2
For date and datetime fields, an exact ISO 8601 week-numbering year match.
Allows chaining additional field lookups. Takes an integer year.
Example::
Entry.objects.filter(pub_date__iso_year=2005)
Entry.objects.filter(pub_date__iso_year__gte=2005)
(The exact SQL syntax varies for each database engine.)
When :setting:`USE_TZ` is ``True``, datetime fields are converted to the
current time zone before filtering.
.. fieldlookup:: month .. fieldlookup:: month
``month`` ``month``
......
...@@ -189,6 +189,11 @@ Models ...@@ -189,6 +189,11 @@ Models
:meth:`.QuerySet.bulk_create` to ``True`` tells the database to ignore :meth:`.QuerySet.bulk_create` to ``True`` tells the database to ignore
failure to insert rows that fail uniqueness constraints or other checks. failure to insert rows that fail uniqueness constraints or other checks.
* The new :class:`~django.db.models.functions.ExtractIsoYear` function extracts
ISO-8601 week-numbering years from :class:`~django.db.models.DateField` and
:class:`~django.db.models.DateTimeField`, and the new :lookup:`iso_year`
lookup allows querying by an ISO-8601 week-numbering year.
Requests and Responses Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
......
...@@ -7,10 +7,10 @@ from django.db.models import ( ...@@ -7,10 +7,10 @@ from django.db.models import (
DateField, DateTimeField, IntegerField, Max, OuterRef, Subquery, TimeField, DateField, DateTimeField, IntegerField, Max, OuterRef, Subquery, TimeField,
) )
from django.db.models.functions import ( from django.db.models.functions import (
Extract, ExtractDay, ExtractHour, ExtractMinute, ExtractMonth, Extract, ExtractDay, ExtractHour, ExtractIsoYear, ExtractMinute,
ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay, ExtractYear, ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay,
Trunc, TruncDate, TruncDay, TruncHour, TruncMinute, TruncMonth, ExtractYear, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute,
TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear, TruncMonth, TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear,
) )
from django.test import ( from django.test import (
TestCase, override_settings, skipIfDBFeature, skipUnlessDBFeature, TestCase, override_settings, skipIfDBFeature, skipUnlessDBFeature,
...@@ -86,21 +86,21 @@ class DateFunctionTests(TestCase): ...@@ -86,21 +86,21 @@ class DateFunctionTests(TestCase):
self.create_model(start_datetime, end_datetime) self.create_model(start_datetime, end_datetime)
self.create_model(end_datetime, start_datetime) self.create_model(end_datetime, start_datetime)
qs = DTModel.objects.filter(start_datetime__year__exact=2015) for lookup in ('year', 'iso_year'):
with self.subTest(lookup):
qs = DTModel.objects.filter(**{'start_datetime__%s__exact' % lookup: 2015})
self.assertEqual(qs.count(), 1) self.assertEqual(qs.count(), 1)
query_string = str(qs.query).lower() query_string = str(qs.query).lower()
self.assertEqual(query_string.count(' between '), 1) self.assertEqual(query_string.count(' between '), 1)
self.assertEqual(query_string.count('extract'), 0) self.assertEqual(query_string.count('extract'), 0)
# exact is implied and should be the same # exact is implied and should be the same
qs = DTModel.objects.filter(start_datetime__year=2015) qs = DTModel.objects.filter(**{'start_datetime__%s' % lookup: 2015})
self.assertEqual(qs.count(), 1) self.assertEqual(qs.count(), 1)
query_string = str(qs.query).lower() query_string = str(qs.query).lower()
self.assertEqual(query_string.count(' between '), 1) self.assertEqual(query_string.count(' between '), 1)
self.assertEqual(query_string.count('extract'), 0) self.assertEqual(query_string.count('extract'), 0)
# date and datetime fields should behave the same # date and datetime fields should behave the same
qs = DTModel.objects.filter(start_date__year=2015) qs = DTModel.objects.filter(**{'start_date__%s' % lookup: 2015})
self.assertEqual(qs.count(), 1) self.assertEqual(qs.count(), 1)
query_string = str(qs.query).lower() query_string = str(qs.query).lower()
self.assertEqual(query_string.count(' between '), 1) self.assertEqual(query_string.count(' between '), 1)
...@@ -115,10 +115,12 @@ class DateFunctionTests(TestCase): ...@@ -115,10 +115,12 @@ class DateFunctionTests(TestCase):
self.create_model(start_datetime, end_datetime) self.create_model(start_datetime, end_datetime)
self.create_model(end_datetime, start_datetime) self.create_model(end_datetime, start_datetime)
qs = DTModel.objects.filter(start_datetime__year__gt=2015) for lookup in ('year', 'iso_year'):
with self.subTest(lookup):
qs = DTModel.objects.filter(**{'start_datetime__%s__gt' % lookup: 2015})
self.assertEqual(qs.count(), 1) self.assertEqual(qs.count(), 1)
self.assertEqual(str(qs.query).lower().count('extract'), 0) self.assertEqual(str(qs.query).lower().count('extract'), 0)
qs = DTModel.objects.filter(start_datetime__year__gte=2015) qs = DTModel.objects.filter(**{'start_datetime__%s__gte' % lookup: 2015})
self.assertEqual(qs.count(), 2) self.assertEqual(qs.count(), 2)
self.assertEqual(str(qs.query).lower().count('extract'), 0) self.assertEqual(str(qs.query).lower().count('extract'), 0)
...@@ -131,10 +133,12 @@ class DateFunctionTests(TestCase): ...@@ -131,10 +133,12 @@ class DateFunctionTests(TestCase):
self.create_model(start_datetime, end_datetime) self.create_model(start_datetime, end_datetime)
self.create_model(end_datetime, start_datetime) self.create_model(end_datetime, start_datetime)
qs = DTModel.objects.filter(start_datetime__year__lt=2016) for lookup in ('year', 'iso_year'):
with self.subTest(lookup):
qs = DTModel.objects.filter(**{'start_datetime__%s__lt' % lookup: 2016})
self.assertEqual(qs.count(), 1) self.assertEqual(qs.count(), 1)
self.assertEqual(str(qs.query).count('extract'), 0) self.assertEqual(str(qs.query).count('extract'), 0)
qs = DTModel.objects.filter(start_datetime__year__lte=2016) qs = DTModel.objects.filter(**{'start_datetime__%s__lte' % lookup: 2016})
self.assertEqual(qs.count(), 2) self.assertEqual(qs.count(), 2)
self.assertEqual(str(qs.query).count('extract'), 0) self.assertEqual(str(qs.query).count('extract'), 0)
...@@ -261,6 +265,51 @@ class DateFunctionTests(TestCase): ...@@ -261,6 +265,51 @@ class DateFunctionTests(TestCase):
) )
self.assertEqual(DTModel.objects.filter(start_datetime__year=ExtractYear('start_datetime')).count(), 2) self.assertEqual(DTModel.objects.filter(start_datetime__year=ExtractYear('start_datetime')).count(), 2)
def test_extract_iso_year_func(self):
start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321)
end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123)
if settings.USE_TZ:
start_datetime = timezone.make_aware(start_datetime, is_dst=False)
end_datetime = timezone.make_aware(end_datetime, is_dst=False)
self.create_model(start_datetime, end_datetime)
self.create_model(end_datetime, start_datetime)
self.assertQuerysetEqual(
DTModel.objects.annotate(extracted=ExtractIsoYear('start_datetime')).order_by('start_datetime'),
[(start_datetime, start_datetime.year), (end_datetime, end_datetime.year)],
lambda m: (m.start_datetime, m.extracted)
)
self.assertQuerysetEqual(
DTModel.objects.annotate(extracted=ExtractIsoYear('start_date')).order_by('start_datetime'),
[(start_datetime, start_datetime.year), (end_datetime, end_datetime.year)],
lambda m: (m.start_datetime, m.extracted)
)
# Both dates are from the same week year.
self.assertEqual(DTModel.objects.filter(start_datetime__iso_year=ExtractIsoYear('start_datetime')).count(), 2)
def test_extract_iso_year_func_boundaries(self):
end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123)
if settings.USE_TZ:
end_datetime = timezone.make_aware(end_datetime, is_dst=False)
week_52_day_2014 = datetime(2014, 12, 27, 13, 0) # Sunday
week_1_day_2014_2015 = datetime(2014, 12, 31, 13, 0) # Wednesday
week_53_day_2015 = datetime(2015, 12, 31, 13, 0) # Thursday
if settings.USE_TZ:
week_1_day_2014_2015 = timezone.make_aware(week_1_day_2014_2015, is_dst=False)
week_52_day_2014 = timezone.make_aware(week_52_day_2014, is_dst=False)
week_53_day_2015 = timezone.make_aware(week_53_day_2015, is_dst=False)
days = [week_52_day_2014, week_1_day_2014_2015, week_53_day_2015]
self.create_model(week_53_day_2015, end_datetime)
self.create_model(week_52_day_2014, end_datetime)
self.create_model(week_1_day_2014_2015, end_datetime)
qs = DTModel.objects.filter(start_datetime__in=days).annotate(
extracted=ExtractIsoYear('start_datetime'),
).order_by('start_datetime')
self.assertQuerysetEqual(qs, [
(week_52_day_2014, 2014),
(week_1_day_2014_2015, 2015),
(week_53_day_2015, 2015),
], lambda m: (m.start_datetime, m.extracted))
def test_extract_month_func(self): def test_extract_month_func(self):
start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321)
end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123)
...@@ -902,6 +951,7 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests): ...@@ -902,6 +951,7 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
day=Extract('start_datetime', 'day'), day=Extract('start_datetime', 'day'),
day_melb=Extract('start_datetime', 'day', tzinfo=melb), day_melb=Extract('start_datetime', 'day', tzinfo=melb),
week=Extract('start_datetime', 'week', tzinfo=melb), week=Extract('start_datetime', 'week', tzinfo=melb),
isoyear=ExtractIsoYear('start_datetime', tzinfo=melb),
weekday=ExtractWeekDay('start_datetime'), weekday=ExtractWeekDay('start_datetime'),
weekday_melb=ExtractWeekDay('start_datetime', tzinfo=melb), weekday_melb=ExtractWeekDay('start_datetime', tzinfo=melb),
quarter=ExtractQuarter('start_datetime', tzinfo=melb), quarter=ExtractQuarter('start_datetime', tzinfo=melb),
...@@ -913,6 +963,7 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests): ...@@ -913,6 +963,7 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
self.assertEqual(utc_model.day, 15) self.assertEqual(utc_model.day, 15)
self.assertEqual(utc_model.day_melb, 16) self.assertEqual(utc_model.day_melb, 16)
self.assertEqual(utc_model.week, 25) self.assertEqual(utc_model.week, 25)
self.assertEqual(utc_model.isoyear, 2015)
self.assertEqual(utc_model.weekday, 2) self.assertEqual(utc_model.weekday, 2)
self.assertEqual(utc_model.weekday_melb, 3) self.assertEqual(utc_model.weekday_melb, 3)
self.assertEqual(utc_model.quarter, 2) self.assertEqual(utc_model.quarter, 2)
...@@ -925,6 +976,7 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests): ...@@ -925,6 +976,7 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
self.assertEqual(melb_model.day, 16) self.assertEqual(melb_model.day, 16)
self.assertEqual(melb_model.day_melb, 16) self.assertEqual(melb_model.day_melb, 16)
self.assertEqual(melb_model.week, 25) self.assertEqual(melb_model.week, 25)
self.assertEqual(melb_model.isoyear, 2015)
self.assertEqual(melb_model.weekday, 3) self.assertEqual(melb_model.weekday, 3)
self.assertEqual(melb_model.quarter, 2) self.assertEqual(melb_model.quarter, 2)
self.assertEqual(melb_model.weekday_melb, 3) self.assertEqual(melb_model.weekday_melb, 3)
......
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