1
0
mirror of https://github.com/django/django.git synced 2025-01-03 15:06:09 +00:00

Fixed #30821 -- Added ExtractIsoWeekYear database function and iso_week_day lookup.

This commit is contained in:
Anatol Ulrich 2019-10-01 00:12:19 +02:00 committed by Mariusz Felisiak
parent e1aa932802
commit 8ed6788aa4
11 changed files with 152 additions and 30 deletions

View File

@ -36,8 +36,10 @@ class DatabaseOperations(BaseDatabaseOperations):
# https://dev.mysql.com/doc/mysql/en/date-and-time-functions.html # https://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
if lookup_type == 'week_day': if lookup_type == 'week_day':
# DAYOFWEEK() returns an integer, 1-7, Sunday=1. # DAYOFWEEK() returns an integer, 1-7, Sunday=1.
# Note: WEEKDAY() returns 0-6, Monday=0.
return "DAYOFWEEK(%s)" % field_name return "DAYOFWEEK(%s)" % field_name
elif lookup_type == 'iso_week_day':
# WEEKDAY() returns an integer, 0-6, Monday=0.
return "WEEKDAY(%s) + 1" % field_name
elif lookup_type == 'week': elif lookup_type == 'week':
# Override the value of default_week_format for consistency with # Override the value of default_week_format for consistency with
# other database backends. # other database backends.

View File

@ -74,6 +74,8 @@ END;
if lookup_type == 'week_day': if lookup_type == 'week_day':
# TO_CHAR(field, 'D') returns an integer from 1-7, where 1=Sunday. # TO_CHAR(field, 'D') returns an integer from 1-7, where 1=Sunday.
return "TO_CHAR(%s, 'D')" % field_name return "TO_CHAR(%s, 'D')" % field_name
elif lookup_type == 'iso_week_day':
return "TO_CHAR(%s - 1, 'D')" % field_name
elif lookup_type == 'week': elif lookup_type == 'week':
# IW = ISO week number # IW = ISO week number
return "TO_CHAR(%s, 'IW')" % field_name return "TO_CHAR(%s, 'IW')" % field_name

View File

@ -32,6 +32,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_week_day':
return "EXTRACT('isodow' FROM %s)" % field_name
elif lookup_type == 'iso_year': elif lookup_type == 'iso_year':
return "EXTRACT('isoyear' FROM %s)" % field_name return "EXTRACT('isoyear' FROM %s)" % field_name
else: else:

View File

@ -478,6 +478,8 @@ def _sqlite_datetime_extract(lookup_type, dt, tzname=None, conn_tzname=None):
return None return None
if lookup_type == 'week_day': if lookup_type == 'week_day':
return (dt.isoweekday() % 7) + 1 return (dt.isoweekday() % 7) + 1
elif lookup_type == 'iso_week_day':
return dt.isoweekday()
elif lookup_type == 'week': elif lookup_type == 'week':
return dt.isocalendar()[1] return dt.isocalendar()[1]
elif lookup_type == 'quarter': elif lookup_type == 'quarter':

View File

@ -1,9 +1,10 @@
from .comparison import Cast, Coalesce, Greatest, Least, NullIf from .comparison import Cast, Coalesce, Greatest, Least, NullIf
from .datetime import ( from .datetime import (
Extract, ExtractDay, ExtractHour, ExtractIsoYear, ExtractMinute, Extract, ExtractDay, ExtractHour, ExtractIsoWeekDay, ExtractIsoYear,
ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay, ExtractMinute, ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek,
ExtractYear, Now, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute, ExtractWeekDay, ExtractYear, Now, Trunc, TruncDate, TruncDay, TruncHour,
TruncMonth, TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear, TruncMinute, 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,11 +25,11 @@ __all__ = [
'Cast', 'Coalesce', 'Greatest', 'Least', 'NullIf', 'Cast', 'Coalesce', 'Greatest', 'Least', 'NullIf',
# datetime # datetime
'Extract', 'ExtractDay', 'ExtractHour', 'ExtractMinute', 'ExtractMonth', 'Extract', 'ExtractDay', 'ExtractHour', 'ExtractMinute', 'ExtractMonth',
'ExtractQuarter', 'ExtractSecond', 'ExtractWeek', 'ExtractWeekDay', 'ExtractQuarter', 'ExtractSecond', 'ExtractWeek', 'ExtractIsoWeekDay',
'ExtractIsoYear', 'ExtractYear', 'Now', 'Trunc', 'TruncDate', 'TruncDay', 'ExtractWeekDay', 'ExtractIsoYear', 'ExtractYear', 'Now', 'Trunc',
'TruncHour', 'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncDate', 'TruncDay', 'TruncHour', 'TruncMinute', 'TruncMonth',
'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncTime', 'TruncQuarter', 'TruncSecond', 'TruncMinute', 'TruncMonth', 'TruncQuarter',
'TruncWeek', 'TruncYear', 'TruncSecond', 'TruncTime', 'TruncWeek', 'TruncYear',
# math # math
'Abs', 'ACos', 'ASin', 'ATan', 'ATan2', 'Ceil', 'Cos', 'Cot', 'Degrees', 'Abs', 'ACos', 'ASin', 'ATan', 'ATan2', 'Ceil', 'Cos', 'Cot', 'Degrees',
'Exp', 'Floor', 'Ln', 'Log', 'Mod', 'Pi', 'Power', 'Radians', 'Round', 'Exp', 'Floor', 'Ln', 'Log', 'Mod', 'Pi', 'Power', 'Radians', 'Round',

View File

@ -75,7 +75,7 @@ class Extract(TimezoneMixin, Transform):
) )
if ( if (
isinstance(field, DurationField) and isinstance(field, DurationField) and
copy.lookup_name in ('year', 'iso_year', 'month', 'week', 'week_day', 'quarter') copy.lookup_name in ('year', 'iso_year', 'month', 'week', 'week_day', 'iso_week_day', 'quarter')
): ):
raise ValueError( raise ValueError(
"Cannot extract component '%s' from DurationField '%s'." "Cannot extract component '%s' from DurationField '%s'."
@ -118,6 +118,11 @@ class ExtractWeekDay(Extract):
lookup_name = 'week_day' lookup_name = 'week_day'
class ExtractIsoWeekDay(Extract):
"""Return Monday=1 through Sunday=7, based on ISO-8601."""
lookup_name = 'iso_week_day'
class ExtractQuarter(Extract): class ExtractQuarter(Extract):
lookup_name = 'quarter' lookup_name = 'quarter'
@ -138,6 +143,7 @@ DateField.register_lookup(ExtractYear)
DateField.register_lookup(ExtractMonth) DateField.register_lookup(ExtractMonth)
DateField.register_lookup(ExtractDay) DateField.register_lookup(ExtractDay)
DateField.register_lookup(ExtractWeekDay) DateField.register_lookup(ExtractWeekDay)
DateField.register_lookup(ExtractIsoWeekDay)
DateField.register_lookup(ExtractWeek) DateField.register_lookup(ExtractWeek)
DateField.register_lookup(ExtractIsoYear) DateField.register_lookup(ExtractIsoYear)
DateField.register_lookup(ExtractQuarter) DateField.register_lookup(ExtractQuarter)

View File

@ -205,6 +205,7 @@ Given the datetime ``2015-06-15 23:30:01.000321+00:00``, the built-in
* "day": 15 * "day": 15
* "week": 25 * "week": 25
* "week_day": 2 * "week_day": 2
* "iso_week_day": 1
* "hour": 23 * "hour": 23
* "minute": 30 * "minute": 30
* "second": 1 * "second": 1
@ -216,6 +217,7 @@ returned when this timezone is active will be the same as above except for:
* "day": 16 * "day": 16
* "week_day": 3 * "week_day": 3
* "iso_week_day": 2
* "hour": 9 * "hour": 9
.. admonition:: ``week_day`` values .. admonition:: ``week_day`` values
@ -288,6 +290,15 @@ Usage example::
.. attribute:: lookup_name = 'week_day' .. attribute:: lookup_name = 'week_day'
.. class:: ExtractIsoWeekDay(expression, tzinfo=None, **extra)
.. versionadded:: 3.1
Returns the ISO-8601 week day with day 1 being Monday and day 7 being
Sunday.
.. attribute:: lookup_name = 'iso_week_day'
.. class:: ExtractWeek(expression, tzinfo=None, **extra) .. class:: ExtractWeek(expression, tzinfo=None, **extra)
.. attribute:: lookup_name = 'week' .. attribute:: lookup_name = 'week'
@ -307,7 +318,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, ExtractIsoYear, ExtractYear, ... ExtractIsoWeekDay, 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)
@ -322,11 +333,13 @@ that deal with date-parts can be used with ``DateField``::
... 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', 'isoyear', 'quarter', 'month', 'week', 'day', 'weekday').get( ... isoweekday=ExtractIsoWeekDay('start_date'),
... end_date__year=ExtractYear('start_date'), ... ).values(
... ) ... 'year', 'isoyear', 'quarter', 'month', 'week', 'day', 'weekday',
... 'isoweekday',
... ).get(end_date__year=ExtractYear('start_date'))
{'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25, {'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25,
'day': 15, 'weekday': 2} 'day': 15, 'weekday': 2, 'isoweekday': 1}
``DateTimeField`` extracts ``DateTimeField`` extracts
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -356,8 +369,8 @@ Each class is also a ``Transform`` registered on ``DateTimeField`` as
>>> from django.utils import timezone >>> from django.utils import timezone
>>> from django.db.models.functions import ( >>> from django.db.models.functions import (
... ExtractDay, ExtractHour, ExtractMinute, ExtractMonth, ... ExtractDay, ExtractHour, ExtractMinute, ExtractMonth,
... ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay, ... ExtractQuarter, ExtractSecond, ExtractWeek, ExtractIsoWeekDay,
... ExtractIsoYear, 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)
@ -372,15 +385,17 @@ Each class is also a ``Transform`` registered on ``DateTimeField`` as
... week=ExtractWeek('start_datetime'), ... week=ExtractWeek('start_datetime'),
... day=ExtractDay('start_datetime'), ... day=ExtractDay('start_datetime'),
... weekday=ExtractWeekDay('start_datetime'), ... weekday=ExtractWeekDay('start_datetime'),
... isoweekday=ExtractIsoWeekDay('start_datetime'),
... hour=ExtractHour('start_datetime'), ... hour=ExtractHour('start_datetime'),
... minute=ExtractMinute('start_datetime'), ... minute=ExtractMinute('start_datetime'),
... second=ExtractSecond('start_datetime'), ... second=ExtractSecond('start_datetime'),
... ).values( ... ).values(
... 'year', 'isoyear', 'month', 'week', 'day', ... 'year', 'isoyear', 'month', 'week', 'day',
... 'weekday', 'hour', 'minute', 'second', ... 'weekday', 'isoweekday', 'hour', 'minute', 'second',
... ).get(end_datetime__year=ExtractYear('start_datetime')) ... ).get(end_datetime__year=ExtractYear('start_datetime'))
{'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25, {'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25,
'day': 15, 'weekday': 2, 'hour': 23, 'minute': 30, 'second': 1} 'day': 15, 'weekday': 2, 'isoweekday': 1, '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
@ -394,11 +409,12 @@ values that are returned::
... Experiment.objects.annotate( ... Experiment.objects.annotate(
... day=ExtractDay('start_datetime'), ... day=ExtractDay('start_datetime'),
... weekday=ExtractWeekDay('start_datetime'), ... weekday=ExtractWeekDay('start_datetime'),
... isoweekday=ExtractIsoWeekDay('start_datetime'),
... hour=ExtractHour('start_datetime'), ... hour=ExtractHour('start_datetime'),
... ).values('day', 'weekday', 'hour').get( ... ).values('day', 'weekday', 'isoweekday', 'hour').get(
... end_datetime__year=ExtractYear('start_datetime'), ... end_datetime__year=ExtractYear('start_datetime'),
... ) ... )
{'day': 16, 'weekday': 3, 'hour': 9} {'day': 16, 'weekday': 3, 'isoweekday': 2, 'hour': 9}
Explicitly passing the timezone to the ``Extract`` function behaves in the same Explicitly passing the timezone to the ``Extract`` function behaves in the same
way, and takes priority over an active timezone:: way, and takes priority over an active timezone::
@ -408,11 +424,12 @@ way, and takes priority over an active timezone::
>>> Experiment.objects.annotate( >>> Experiment.objects.annotate(
... day=ExtractDay('start_datetime', tzinfo=melb), ... day=ExtractDay('start_datetime', tzinfo=melb),
... weekday=ExtractWeekDay('start_datetime', tzinfo=melb), ... weekday=ExtractWeekDay('start_datetime', tzinfo=melb),
... isoweekday=ExtractIsoWeekDay('start_datetime', tzinfo=melb),
... hour=ExtractHour('start_datetime', tzinfo=melb), ... hour=ExtractHour('start_datetime', tzinfo=melb),
... ).values('day', 'weekday', 'hour').get( ... ).values('day', 'weekday', 'isoweekday', 'hour').get(
... end_datetime__year=ExtractYear('start_datetime'), ... end_datetime__year=ExtractYear('start_datetime'),
... ) ... )
{'day': 16, 'weekday': 3, 'hour': 9} {'day': 16, 'weekday': 3, 'isoweekday': 2, 'hour': 9}
``Now`` ``Now``
------- -------

View File

@ -3110,6 +3110,35 @@ When :setting:`USE_TZ` is ``True``, datetime fields are converted to the
current time zone before filtering. This requires :ref:`time zone definitions current time zone before filtering. This requires :ref:`time zone definitions
in the database <database-time-zone-definitions>`. in the database <database-time-zone-definitions>`.
.. fieldlookup:: iso_week_day
``iso_week_day``
~~~~~~~~~~~~~~~~
.. versionadded:: 3.1
For date and datetime fields, an exact ISO 8601 day of the week match. Allows
chaining additional field lookups.
Takes an integer value representing the day of the week from 1 (Monday) to 7
(Sunday).
Example::
Entry.objects.filter(pub_date__iso_week_day=1)
Entry.objects.filter(pub_date__iso_week_day__gte=1)
(No equivalent SQL code fragment is included for this lookup because
implementation of the relevant query varies among different database engines.)
Note this will match any record with a ``pub_date`` that falls on a Monday (day
1 of the week), regardless of the month or year in which it occurs. Week days
are indexed with day 1 being Monday and day 7 being Sunday.
When :setting:`USE_TZ` is ``True``, datetime fields are converted to the
current time zone before filtering. This requires :ref:`time zone definitions
in the database <database-time-zone-definitions>`.
.. fieldlookup:: quarter .. fieldlookup:: quarter
``quarter`` ``quarter``

View File

@ -160,7 +160,10 @@ Migrations
Models Models
~~~~~~ ~~~~~~
* ... * The new :class:`~django.db.models.functions.ExtractIsoWeekDay` function
extracts ISO-8601 week days from :class:`~django.db.models.DateField` and
:class:`~django.db.models.DateTimeField`, and the new :lookup:`iso_week_day`
lookup allows querying by an ISO-8601 day of week.
Pagination Pagination
~~~~~~~~~~ ~~~~~~~~~~

View File

@ -8,10 +8,11 @@ from django.db.models import (
TimeField, TimeField,
) )
from django.db.models.functions import ( from django.db.models.functions import (
Extract, ExtractDay, ExtractHour, ExtractIsoYear, ExtractMinute, Extract, ExtractDay, ExtractHour, ExtractIsoWeekDay, ExtractIsoYear,
ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay, ExtractMinute, ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek,
ExtractYear, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute, ExtractWeekDay, ExtractYear, Trunc, TruncDate, TruncDay, TruncHour,
TruncMonth, TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear, TruncMinute, TruncMonth, TruncQuarter, TruncSecond, TruncTime, TruncWeek,
TruncYear,
) )
from django.test import ( from django.test import (
TestCase, override_settings, skipIfDBFeature, skipUnlessDBFeature, TestCase, override_settings, skipIfDBFeature, skipUnlessDBFeature,
@ -217,6 +218,16 @@ class DateFunctionTests(TestCase):
], ],
lambda m: (m.start_datetime, m.extracted) lambda m: (m.start_datetime, m.extracted)
) )
self.assertQuerysetEqual(
DTModel.objects.annotate(
extracted=Extract('start_datetime', 'iso_week_day'),
).order_by('start_datetime'),
[
(start_datetime, start_datetime.isoweekday()),
(end_datetime, end_datetime.isoweekday()),
],
lambda m: (m.start_datetime, m.extracted)
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
DTModel.objects.annotate(extracted=Extract('start_datetime', 'hour')).order_by('start_datetime'), DTModel.objects.annotate(extracted=Extract('start_datetime', 'hour')).order_by('start_datetime'),
[(start_datetime, start_datetime.hour), (end_datetime, end_datetime.hour)], [(start_datetime, start_datetime.hour), (end_datetime, end_datetime.hour)],
@ -275,7 +286,10 @@ class DateFunctionTests(TestCase):
def test_extract_duration_unsupported_lookups(self): def test_extract_duration_unsupported_lookups(self):
msg = "Cannot extract component '%s' from DurationField 'duration'." msg = "Cannot extract component '%s' from DurationField 'duration'."
for lookup in ('year', 'iso_year', 'month', 'week', 'week_day', 'quarter'): for lookup in (
'year', 'iso_year', 'month', 'week', 'week_day', 'iso_week_day',
'quarter',
):
with self.subTest(lookup): with self.subTest(lookup):
with self.assertRaisesMessage(ValueError, msg % lookup): with self.assertRaisesMessage(ValueError, msg % lookup):
DTModel.objects.annotate(extracted=Extract('duration', lookup)) DTModel.objects.annotate(extracted=Extract('duration', lookup))
@ -499,6 +513,41 @@ class DateFunctionTests(TestCase):
) )
self.assertEqual(DTModel.objects.filter(start_datetime__week_day=ExtractWeekDay('start_datetime')).count(), 2) self.assertEqual(DTModel.objects.filter(start_datetime__week_day=ExtractWeekDay('start_datetime')).count(), 2)
def test_extract_iso_weekday_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=ExtractIsoWeekDay('start_datetime'),
).order_by('start_datetime'),
[
(start_datetime, start_datetime.isoweekday()),
(end_datetime, end_datetime.isoweekday()),
],
lambda m: (m.start_datetime, m.extracted)
)
self.assertQuerysetEqual(
DTModel.objects.annotate(
extracted=ExtractIsoWeekDay('start_date'),
).order_by('start_datetime'),
[
(start_datetime, start_datetime.isoweekday()),
(end_datetime, end_datetime.isoweekday()),
],
lambda m: (m.start_datetime, m.extracted)
)
self.assertEqual(
DTModel.objects.filter(
start_datetime__week_day=ExtractWeekDay('start_datetime'),
).count(),
2,
)
def test_extract_hour_func(self): def test_extract_hour_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)
@ -1005,6 +1054,8 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
isoyear=ExtractIsoYear('start_datetime', 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),
isoweekday=ExtractIsoWeekDay('start_datetime'),
isoweekday_melb=ExtractIsoWeekDay('start_datetime', tzinfo=melb),
quarter=ExtractQuarter('start_datetime', tzinfo=melb), quarter=ExtractQuarter('start_datetime', tzinfo=melb),
hour=ExtractHour('start_datetime'), hour=ExtractHour('start_datetime'),
hour_melb=ExtractHour('start_datetime', tzinfo=melb), hour_melb=ExtractHour('start_datetime', tzinfo=melb),
@ -1020,6 +1071,8 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
self.assertEqual(utc_model.isoyear, 2015) 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.isoweekday, 1)
self.assertEqual(utc_model.isoweekday_melb, 2)
self.assertEqual(utc_model.quarter, 2) self.assertEqual(utc_model.quarter, 2)
self.assertEqual(utc_model.hour, 23) self.assertEqual(utc_model.hour, 23)
self.assertEqual(utc_model.hour_melb, 9) self.assertEqual(utc_model.hour_melb, 9)
@ -1035,8 +1088,10 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
self.assertEqual(melb_model.week, 25) self.assertEqual(melb_model.week, 25)
self.assertEqual(melb_model.isoyear, 2015) self.assertEqual(melb_model.isoyear, 2015)
self.assertEqual(melb_model.weekday, 3) self.assertEqual(melb_model.weekday, 3)
self.assertEqual(melb_model.isoweekday, 2)
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)
self.assertEqual(melb_model.isoweekday_melb, 2)
self.assertEqual(melb_model.hour, 9) self.assertEqual(melb_model.hour, 9)
self.assertEqual(melb_model.hour_melb, 9) self.assertEqual(melb_model.hour_melb, 9)

View File

@ -153,6 +153,7 @@ class LegacyDatabaseTests(TestCase):
self.assertEqual(Event.objects.filter(dt__month=1).count(), 2) self.assertEqual(Event.objects.filter(dt__month=1).count(), 2)
self.assertEqual(Event.objects.filter(dt__day=1).count(), 2) self.assertEqual(Event.objects.filter(dt__day=1).count(), 2)
self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 2) self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 2)
self.assertEqual(Event.objects.filter(dt__iso_week_day=6).count(), 2)
self.assertEqual(Event.objects.filter(dt__hour=1).count(), 1) self.assertEqual(Event.objects.filter(dt__hour=1).count(), 1)
self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2) self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2)
self.assertEqual(Event.objects.filter(dt__second=0).count(), 2) self.assertEqual(Event.objects.filter(dt__second=0).count(), 2)
@ -366,6 +367,7 @@ class NewDatabaseTests(TestCase):
self.assertEqual(Event.objects.filter(dt__month=1).count(), 2) self.assertEqual(Event.objects.filter(dt__month=1).count(), 2)
self.assertEqual(Event.objects.filter(dt__day=1).count(), 2) self.assertEqual(Event.objects.filter(dt__day=1).count(), 2)
self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 2) self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 2)
self.assertEqual(Event.objects.filter(dt__iso_week_day=6).count(), 2)
self.assertEqual(Event.objects.filter(dt__hour=1).count(), 1) self.assertEqual(Event.objects.filter(dt__hour=1).count(), 1)
self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2) self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2)
self.assertEqual(Event.objects.filter(dt__second=0).count(), 2) self.assertEqual(Event.objects.filter(dt__second=0).count(), 2)
@ -381,6 +383,7 @@ class NewDatabaseTests(TestCase):
self.assertEqual(Event.objects.filter(dt__month=1).count(), 1) self.assertEqual(Event.objects.filter(dt__month=1).count(), 1)
self.assertEqual(Event.objects.filter(dt__day=1).count(), 1) self.assertEqual(Event.objects.filter(dt__day=1).count(), 1)
self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 1) self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 1)
self.assertEqual(Event.objects.filter(dt__iso_week_day=6).count(), 1)
self.assertEqual(Event.objects.filter(dt__hour=22).count(), 1) self.assertEqual(Event.objects.filter(dt__hour=22).count(), 1)
self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2) self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2)
self.assertEqual(Event.objects.filter(dt__second=0).count(), 2) self.assertEqual(Event.objects.filter(dt__second=0).count(), 2)