1515from django import VERSION as django_version
1616import pytz
1717
18+ DJANGO41 = django_version >= (4 , 1 )
19+
1820
1921class DatabaseOperations (BaseDatabaseOperations ):
2022 compiler_module = 'mssql.compiler'
@@ -32,6 +34,12 @@ def _convert_field_to_tz(self, field_name, tzname):
3234 field_name = 'DATEADD(second, %d, %s)' % (offset , field_name )
3335 return field_name
3436
37+ def _convert_sql_to_tz (self , sql , params , tzname ):
38+ if tzname and settings .USE_TZ and self .connection .timezone_name != tzname :
39+ offset = self ._get_utcoffset (tzname )
40+ sql = 'DATEADD(second, %d, %s)' % (offset , sql )
41+ return sql , params
42+
3543 def _get_utcoffset (self , tzname ):
3644 """
3745 Returns UTC offset for given time zone in seconds
@@ -125,17 +133,32 @@ def convert_uuidfield_value(self, value, expression, connection):
125133 def convert_booleanfield_value (self , value , expression , connection ):
126134 return bool (value ) if value in (0 , 1 ) else value
127135
128- def date_extract_sql (self , lookup_type , field_name ):
129- if lookup_type == 'week_day' :
130- return "DATEPART(weekday, %s)" % field_name
131- elif lookup_type == 'week' :
132- return "DATEPART(iso_week, %s)" % field_name
133- elif lookup_type == 'iso_week_day' :
134- return "DATEPART(weekday, DATEADD(day, -1, %s))" % field_name
135- elif lookup_type == 'iso_year' :
136- return "YEAR(DATEADD(day, 26 - DATEPART(isoww, %s), %s))" % (field_name , field_name )
137- else :
138- return "DATEPART(%s, %s)" % (lookup_type , field_name )
136+
137+ if DJANGO41 :
138+ def date_extract_sql (self , lookup_type , sql , params ):
139+ if lookup_type == 'week_day' :
140+ sql = "DATEPART(weekday, %s)" % sql
141+ elif lookup_type == 'week' :
142+ sql = "DATEPART(iso_week, %s)" % sql
143+ elif lookup_type == 'iso_week_day' :
144+ sql = "DATEPART(weekday, DATEADD(day, -1, %s))" % sql
145+ elif lookup_type == 'iso_year' :
146+ sql = "YEAR(DATEADD(day, 26 - DATEPART(isoww, %s), %s))" % (sql , sql )
147+ else :
148+ sql = "DATEPART(%s, %s)" % (lookup_type , sql )
149+ return sql , params
150+ else :
151+ def date_extract_sql (self , lookup_type , field_name ):
152+ if lookup_type == 'week_day' :
153+ return "DATEPART(weekday, %s)" % field_name
154+ elif lookup_type == 'week' :
155+ return "DATEPART(iso_week, %s)" % field_name
156+ elif lookup_type == 'iso_week_day' :
157+ return "DATEPART(weekday, DATEADD(day, -1, %s))" % field_name
158+ elif lookup_type == 'iso_year' :
159+ return "YEAR(DATEADD(day, 26 - DATEPART(isoww, %s), %s))" % (field_name , field_name )
160+ else :
161+ return "DATEPART(%s, %s)" % (lookup_type , field_name )
139162
140163 def date_interval_sql (self , timedelta ):
141164 """
@@ -147,50 +170,100 @@ def date_interval_sql(self, timedelta):
147170 sql = 'DATEADD(microsecond, %d%%s, CAST(%s AS datetime2))' % (timedelta .microseconds , sql )
148171 return sql
149172
150- def date_trunc_sql (self , lookup_type , field_name , tzname = None ):
151- field_name = self ._convert_field_to_tz (field_name , tzname )
152- CONVERT_YEAR = 'CONVERT(varchar, DATEPART(year, %s))' % field_name
153- CONVERT_QUARTER = 'CONVERT(varchar, 1+((DATEPART(quarter, %s)-1)*3))' % field_name
154- CONVERT_MONTH = 'CONVERT(varchar, DATEPART(month, %s))' % field_name
155- CONVERT_WEEK = "DATEADD(DAY, (DATEPART(weekday, %s) + 5) %%%% 7 * -1, %s)" % (field_name , field_name )
156-
157- if lookup_type == 'year' :
158- return "CONVERT(datetime2, %s + '/01/01')" % CONVERT_YEAR
159- if lookup_type == 'quarter' :
160- return "CONVERT(datetime2, %s + '/' + %s + '/01')" % (CONVERT_YEAR , CONVERT_QUARTER )
161- if lookup_type == 'month' :
162- return "CONVERT(datetime2, %s + '/' + %s + '/01')" % (CONVERT_YEAR , CONVERT_MONTH )
163- if lookup_type == 'week' :
164- return "CONVERT(datetime2, CONVERT(varchar, %s, 112))" % CONVERT_WEEK
165- if lookup_type == 'day' :
166- return "CONVERT(datetime2, CONVERT(varchar(12), %s, 112))" % field_name
167-
168- def datetime_cast_date_sql (self , field_name , tzname ):
169- field_name = self ._convert_field_to_tz (field_name , tzname )
170- sql = 'CAST(%s AS date)' % field_name
171- return sql
172-
173- def datetime_cast_time_sql (self , field_name , tzname ):
174- field_name = self ._convert_field_to_tz (field_name , tzname )
175- sql = 'CAST(%s AS time)' % field_name
176- return sql
177-
178- def datetime_extract_sql (self , lookup_type , field_name , tzname ):
179- field_name = self ._convert_field_to_tz (field_name , tzname )
180- return self .date_extract_sql (lookup_type , field_name )
181-
182- def datetime_trunc_sql (self , lookup_type , field_name , tzname ):
183- field_name = self ._convert_field_to_tz (field_name , tzname )
184- sql = ''
185- if lookup_type in ('year' , 'quarter' , 'month' , 'week' , 'day' ):
186- sql = self .date_trunc_sql (lookup_type , field_name )
187- elif lookup_type == 'hour' :
188- sql = "CONVERT(datetime2, SUBSTRING(CONVERT(varchar, %s, 20), 0, 14) + ':00:00')" % field_name
189- elif lookup_type == 'minute' :
190- sql = "CONVERT(datetime2, SUBSTRING(CONVERT(varchar, %s, 20), 0, 17) + ':00')" % field_name
191- elif lookup_type == 'second' :
192- sql = "CONVERT(datetime2, CONVERT(varchar, %s, 20))" % field_name
193- return sql
173+ if DJANGO41 :
174+ def date_trunc_sql (self , lookup_type , sql , params , tzname = None ):
175+ sql , params = self ._convert_sql_to_tz (sql , params , tzname )
176+ CONVERT_YEAR = 'CONVERT(varchar, DATEPART(year, %s))' % sql
177+ CONVERT_QUARTER = 'CONVERT(varchar, 1+((DATEPART(quarter, %s)-1)*3))' % sql
178+ CONVERT_MONTH = 'CONVERT(varchar, DATEPART(month, %s))' % sql
179+ CONVERT_WEEK = "DATEADD(DAY, (DATEPART(weekday, %s) + 5) %%%% 7 * -1, %s)" % (sql , sql )
180+
181+ if lookup_type == 'year' :
182+ sql = "CONVERT(datetime2, %s + '/01/01')" % CONVERT_YEAR
183+ if lookup_type == 'quarter' :
184+ sql = "CONVERT(datetime2, %s + '/' + %s + '/01')" % (CONVERT_YEAR , CONVERT_QUARTER )
185+ if lookup_type == 'month' :
186+ sql = "CONVERT(datetime2, %s + '/' + %s + '/01')" % (CONVERT_YEAR , CONVERT_MONTH )
187+ if lookup_type == 'week' :
188+ sql = "CONVERT(datetime2, CONVERT(varchar, %s, 112))" % CONVERT_WEEK
189+ if lookup_type == 'day' :
190+ sql = "CONVERT(datetime2, CONVERT(varchar(12), %s, 112))" % sql
191+ return sql , params
192+ else :
193+ def date_trunc_sql (self , lookup_type , field_name , tzname = None ):
194+ field_name = self ._convert_field_to_tz (field_name , tzname )
195+ CONVERT_YEAR = 'CONVERT(varchar, DATEPART(year, %s))' % field_name
196+ CONVERT_QUARTER = 'CONVERT(varchar, 1+((DATEPART(quarter, %s)-1)*3))' % field_name
197+ CONVERT_MONTH = 'CONVERT(varchar, DATEPART(month, %s))' % field_name
198+ CONVERT_WEEK = "DATEADD(DAY, (DATEPART(weekday, %s) + 5) %%%% 7 * -1, %s)" % (field_name , field_name )
199+
200+ if lookup_type == 'year' :
201+ return "CONVERT(datetime2, %s + '/01/01')" % CONVERT_YEAR
202+ if lookup_type == 'quarter' :
203+ return "CONVERT(datetime2, %s + '/' + %s + '/01')" % (CONVERT_YEAR , CONVERT_QUARTER )
204+ if lookup_type == 'month' :
205+ return "CONVERT(datetime2, %s + '/' + %s + '/01')" % (CONVERT_YEAR , CONVERT_MONTH )
206+ if lookup_type == 'week' :
207+ return "CONVERT(datetime2, CONVERT(varchar, %s, 112))" % CONVERT_WEEK
208+ if lookup_type == 'day' :
209+ return "CONVERT(datetime2, CONVERT(varchar(12), %s, 112))" % field_name
210+
211+ if DJANGO41 :
212+ def datetime_cast_date_sql (self , sql , params , tzname ):
213+ sql , params = self ._convert_sql_to_tz (sql , params , tzname )
214+ sql = 'CAST(%s AS date)' % sql
215+ return sql , params
216+ else :
217+ def datetime_cast_date_sql (self , field_name , tzname ):
218+ field_name = self ._convert_field_to_tz (field_name , tzname )
219+ sql = 'CAST(%s AS date)' % field_name
220+ return sql
221+
222+ if DJANGO41 :
223+ def datetime_cast_time_sql (self , sql , params , tzname ):
224+ sql , params = self ._convert_sql_to_tz (sql , params , tzname )
225+ sql = 'CAST(%s AS time)' % sql
226+ return sql , params
227+ else :
228+ def datetime_cast_time_sql (self , field_name , tzname ):
229+ field_name = self ._convert_field_to_tz (field_name , tzname )
230+ sql = 'CAST(%s AS time)' % field_name
231+ return sql
232+
233+ if DJANGO41 :
234+ def datetime_extract_sql (self , lookup_type , sql , params , tzname ):
235+ sql , params = self ._convert_sql_to_tz (sql , params , tzname )
236+ return self .date_extract_sql (lookup_type , sql , params )
237+ else :
238+ def datetime_extract_sql (self , lookup_type , field_name , tzname ):
239+ field_name = self ._convert_field_to_tz (field_name , tzname )
240+ return self .date_extract_sql (lookup_type , field_name )
241+
242+ if DJANGO41 :
243+ def datetime_trunc_sql (self , lookup_type , sql , params , tzname ):
244+ sql , params = self ._convert_sql_to_tz (sql , params , tzname )
245+ if lookup_type in ('year' , 'quarter' , 'month' , 'week' , 'day' ):
246+ return self .date_trunc_sql (lookup_type , sql , params )
247+ elif lookup_type == 'hour' :
248+ sql = "CONVERT(datetime2, SUBSTRING(CONVERT(varchar, %s, 20), 0, 14) + ':00:00')" % sql
249+ elif lookup_type == 'minute' :
250+ sql = "CONVERT(datetime2, SUBSTRING(CONVERT(varchar, %s, 20), 0, 17) + ':00')" % sql
251+ elif lookup_type == 'second' :
252+ sql = "CONVERT(datetime2, CONVERT(varchar, %s, 20))" % sql
253+ return sql , params
254+ else :
255+ def datetime_trunc_sql (self , lookup_type , field_name , tzname ):
256+ field_name = self ._convert_field_to_tz (field_name , tzname )
257+ sql = ''
258+ if lookup_type in ('year' , 'quarter' , 'month' , 'week' , 'day' ):
259+ sql = self .date_trunc_sql (lookup_type , field_name )
260+ elif lookup_type == 'hour' :
261+ sql = "CONVERT(datetime2, SUBSTRING(CONVERT(varchar, %s, 20), 0, 14) + ':00:00')" % field_name
262+ elif lookup_type == 'minute' :
263+ sql = "CONVERT(datetime2, SUBSTRING(CONVERT(varchar, %s, 20), 0, 17) + ':00')" % field_name
264+ elif lookup_type == 'second' :
265+ sql = "CONVERT(datetime2, CONVERT(varchar, %s, 20))" % field_name
266+ return sql
194267
195268 def fetch_returned_insert_rows (self , cursor ):
196269 """
@@ -494,29 +567,46 @@ def adapt_datetimefield_value(self, value):
494567 # When support for time zones is enabled, Django stores datetime information
495568 # in UTC in the database and uses time-zone-aware objects internally
496569 # source: https://docs.djangoproject.com/en/dev/topics/i18n/timezones/#overview
497- value = value .astimezone (timezone .utc )
570+ value = value .astimezone (datetime . timezone .utc )
498571 else :
499572 # When USE_TZ is False, settings.TIME_ZONE is the time zone in
500573 # which Django will store all datetimes
501574 # source: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TIME_ZONE
502575 value = timezone .make_naive (value , self .connection .timezone )
503576 return value
504577
505- def time_trunc_sql (self , lookup_type , field_name , tzname = '' ):
506- # if self.connection.sql_server_version >= 2012:
507- # fields = {
508- # 'hour': 'DATEPART(hour, %s)' % field_name,
509- # 'minute': 'DATEPART(minute, %s)' % field_name if lookup_type != 'hour' else '0',
510- # 'second': 'DATEPART(second, %s)' % field_name if lookup_type == 'second' else '0',
511- # }
512- # sql = 'TIMEFROMPARTS(%(hour)s, %(minute)s, %(second)s, 0, 0)' % fields
513- if lookup_type == 'hour' :
514- sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 3) + ':00:00')" % field_name
515- elif lookup_type == 'minute' :
516- sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 6) + ':00')" % field_name
517- elif lookup_type == 'second' :
518- sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 9))" % field_name
519- return sql
578+ if DJANGO41 :
579+ def time_trunc_sql (self , lookup_type , sql , params , tzname = None ):
580+ # if self.connection.sql_server_version >= 2012:
581+ # fields = {
582+ # 'hour': 'DATEPART(hour, %s)' % field_name,
583+ # 'minute': 'DATEPART(minute, %s)' % field_name if lookup_type != 'hour' else '0',
584+ # 'second': 'DATEPART(second, %s)' % field_name if lookup_type == 'second' else '0',
585+ # }
586+ # sql = 'TIMEFROMPARTS(%(hour)s, %(minute)s, %(second)s, 0, 0)' % fields
587+ if lookup_type == 'hour' :
588+ sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 3) + ':00:00')" % sql
589+ elif lookup_type == 'minute' :
590+ sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 6) + ':00')" % sql
591+ elif lookup_type == 'second' :
592+ sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 9))" % sql
593+ return sql , params
594+ else :
595+ def time_trunc_sql (self , lookup_type , field_name , tzname = '' ):
596+ # if self.connection.sql_server_version >= 2012:
597+ # fields = {
598+ # 'hour': 'DATEPART(hour, %s)' % field_name,
599+ # 'minute': 'DATEPART(minute, %s)' % field_name if lookup_type != 'hour' else '0',
600+ # 'second': 'DATEPART(second, %s)' % field_name if lookup_type == 'second' else '0',
601+ # }
602+ # sql = 'TIMEFROMPARTS(%(hour)s, %(minute)s, %(second)s, 0, 0)' % fields
603+ if lookup_type == 'hour' :
604+ sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 3) + ':00:00')" % field_name
605+ elif lookup_type == 'minute' :
606+ sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 6) + ':00')" % field_name
607+ elif lookup_type == 'second' :
608+ sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 9))" % field_name
609+ return sql
520610
521611 def conditional_expression_supported_in_where_clause (self , expression ):
522612 """
0 commit comments