|
1 | 1 | import datetime |
2 | 2 | import time |
3 | 3 | import uuid |
| 4 | +import warnings |
4 | 5 |
|
5 | 6 | from django.conf import settings |
6 | 7 | from django.db.backends.base.operations import BaseDatabaseOperations |
@@ -33,6 +34,15 @@ def _get_utcoffset(self, tzname): |
33 | 34 | delta = zone.localize(now, is_dst=False).utcoffset() |
34 | 35 | return delta.days * 86400 + delta.seconds |
35 | 36 |
|
| 37 | + def _warn_legacy_driver(self, sqltype): |
| 38 | + warnings.warn( |
| 39 | + 'A %s value was received as a string. This is because you ' |
| 40 | + 'are now using a legacy ODBC driver which does not support ' |
| 41 | + 'this data type while your database has been migrated using it. ' |
| 42 | + 'You should upgrade your ODBC driver for consistency with your ' |
| 43 | + 'database migration.' % sqltype, |
| 44 | + RuntimeWarning) |
| 45 | + |
36 | 46 | def bulk_batch_size(self, fields, objs): |
37 | 47 | """ |
38 | 48 | Returns the maximum allowed batch size for the backend. The fields |
@@ -83,19 +93,40 @@ def combine_expression(self, connector, sub_expressions): |
83 | 93 |
|
84 | 94 | def convert_datefield_value(self, value, expression, connection, context): |
85 | 95 | if value is not None: |
86 | | - if self.connection.use_legacy_datetime: |
| 96 | + # WDAC and old FreeTDS receive a date value as a string |
| 97 | + # http://blogs.msdn.com/b/sqlnativeclient/archive/2008/02/27/microsoft-sql-server-native-client-and-microsoft-sql-server-2008-native-client.aspx |
| 98 | + if isinstance(value, string_types): |
| 99 | + self._warn_legacy_driver('date') |
| 100 | + value = datetime.date(*map(lambda x: int(x), value.split('-'))) |
| 101 | + elif self.connection.use_legacy_datetime: |
87 | 102 | if isinstance(value, datetime.datetime): |
88 | 103 | value = value.date() # extract date |
89 | 104 | return value |
90 | 105 |
|
| 106 | + def convert_datetimefield_value(self, value, expression, connection, context): |
| 107 | + if value is not None: |
| 108 | + # WDAC and old FreeTDS receive a datetime2 value as a string |
| 109 | + # http://blogs.msdn.com/b/sqlnativeclient/archive/2008/02/27/microsoft-sql-server-native-client-and-microsoft-sql-server-2008-native-client.aspx |
| 110 | + if isinstance(value, string_types): |
| 111 | + self._warn_legacy_driver('datetime2') |
| 112 | + value = datetime.datetime.strptime(value[:26], '%Y-%m-%d %H:%M:%S.%f') |
| 113 | + if settings.USE_TZ: |
| 114 | + value = timezone.make_aware(value, timezone.utc) |
| 115 | + return value |
| 116 | + |
91 | 117 | def convert_floatfield_value(self, value, expression, connection, context): |
92 | 118 | if value is not None: |
93 | 119 | value = float(value) |
94 | 120 | return value |
95 | 121 |
|
96 | 122 | def convert_timefield_value(self, value, expression, connection, context): |
97 | 123 | if value is not None: |
98 | | - if self.connection.use_legacy_datetime: |
| 124 | + # WDAC and old FreeTDS receive a time value as a string |
| 125 | + # http://blogs.msdn.com/b/sqlnativeclient/archive/2008/02/27/microsoft-sql-server-native-client-and-microsoft-sql-server-2008-native-client.aspx |
| 126 | + if isinstance(value, string_types): |
| 127 | + self._warn_legacy_driver('time') |
| 128 | + value = datetime.time(*map(lambda x: int(x), value[:15].replace('.', ':').split(':'))) |
| 129 | + elif self.connection.use_legacy_datetime: |
99 | 130 | if (isinstance(value, datetime.datetime) and value.year == 1900 and value.month == value.day == 1): |
100 | 131 | value = value.time() # extract time |
101 | 132 | return value |
@@ -194,6 +225,8 @@ def get_db_converters(self, expression): |
194 | 225 | internal_type = expression.output_field.get_internal_type() |
195 | 226 | if internal_type == 'DateField': |
196 | 227 | converters.append(self.convert_datefield_value) |
| 228 | + if internal_type == 'DateTimeField': |
| 229 | + converters.append(self.convert_datetimefield_value) |
197 | 230 | elif internal_type == 'FloatField': |
198 | 231 | converters.append(self.convert_floatfield_value) |
199 | 232 | elif internal_type == 'TimeField': |
@@ -392,7 +425,7 @@ def value_to_db_datetime(self, value): |
392 | 425 | return None |
393 | 426 | if settings.USE_TZ and timezone.is_aware(value): |
394 | 427 | # pyodbc donesn't support datetimeoffset |
395 | | - value = value.astimezone(timezone.utc) |
| 428 | + value = value.astimezone(timezone.utc).replace(tzinfo=None) |
396 | 429 | if not self.connection.features.supports_microsecond_precision: |
397 | 430 | value = value.replace(microsecond=0) |
398 | 431 | return value |
|
0 commit comments