Ticket #17260: dates_in_tz.diff
File dates_in_tz.diff, 11.6 KB (added by , 13 years ago) |
---|
-
django/db/backends/__init__.py
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 7674f5c..c8f010a 100644
a b 1 import datetime 2 1 3 from django.db.utils import DatabaseError 4 from django.utils import timezone 2 5 3 6 try: 4 7 import thread … … class BaseDatabaseOperations(object): 807 810 808 811 `value` is an int, containing the looked-up year. 809 812 """ 810 first = '%s-01-01 00:00:00' 811 second = '%s-12-31 23:59:59.999999' 812 return [first % value, second % value] 813 tz = timezone.get_current_timezone() if settings.USE_TZ else None 814 first_dt = datetime.datetime(year=value, month=01, day=01, tzinfo=tz) 815 second_dt = datetime.datetime(year=value, month=12, day=31, hour=23, 816 minute=59, second=59, microsecond=999999, 817 tzinfo=tz) 818 if settings.USE_TZ: 819 first_dt = first_dt.astimezone(timezone.utc) 820 second_dt = second_dt.astimezone(timezone.utc) 821 first = first_dt.strftime('%Y-%m-%d %H:%M:%S') 822 second = second_dt.strftime('%Y-%m-%d %H:%M:%S.%f') 823 return [first, second] 813 824 814 825 def year_lookup_bounds_for_date_field(self, value): 815 826 """ -
django/db/backends/postgresql_psycopg2/operations.py
diff --git a/django/db/backends/postgresql_psycopg2/operations.py b/django/db/backends/postgresql_psycopg2/operations.py index 949a05c..861d742 100644
a b 1 1 from django.db.backends import BaseDatabaseOperations 2 from django.conf import settings 3 from django.utils import timezone 2 4 3 5 4 6 class DatabaseOperations(BaseDatabaseOperations): … … class DatabaseOperations(BaseDatabaseOperations): 7 9 8 10 def date_extract_sql(self, lookup_type, field_name): 9 11 # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT 12 field_sql = field_name 13 if settings.USE_TZ: 14 # Hey, I finally managed to get the UTC offset! And in oh-so-beautiful way... 15 # Will this break at DST? 16 time_offset = timezone.now().astimezone(timezone.get_current_timezone()).utcoffset() 17 if time_offset: 18 field_sql = self.date_interval_sql(field_name, '+', time_offset) 10 19 if lookup_type == 'week_day': 11 20 # For consistency across backends, we return Sunday=1, Saturday=7. 12 return "EXTRACT('dow' FROM %s) + 1" % field_ name21 return "EXTRACT('dow' FROM %s) + 1" % field_sql 13 22 else: 14 return "EXTRACT('%s' FROM %s)" % (lookup_type, field_ name)23 return "EXTRACT('%s' FROM %s)" % (lookup_type, field_sql) 15 24 16 25 def date_interval_sql(self, sql, connector, timedelta): 17 26 """ … … class DatabaseOperations(BaseDatabaseOperations): 32 41 33 42 def date_trunc_sql(self, lookup_type, field_name): 34 43 # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC 35 return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name) 44 field_sql = field_name 45 if settings.USE_TZ: 46 # Hey, I finally managed to get the UTC offset! And in oh-so-beautiful way... 47 # Will this break at DST? 48 time_offset = timezone.now().astimezone(timezone.get_current_timezone()).utcoffset() 49 if time_offset: 50 field_sql = self.date_interval_sql(field_name, '+', time_offset) 51 # Alternate way: better except we don't know if PostgreSQL happens to support this 52 # timezone... For example the testing returns +0300 for me, which really isn't a 53 # timezone name :( The above way is a hack at its core, we really don't know if the 54 # offset is correct for the date in the DB. It is likely not going to matter, the 55 # DST offset is usually just one hour. But for example some country can change 56 # their time zone for 23 hours, and that would break date lookups. Maybe a bit 57 # non-realistic problem, but to be totally correct we should use PostgreSQL's at 58 # time zone, not adding the current UTC offset. 59 # field_sql = field_name + " AT TIME ZONE '%s'" % timezone.get_current_timezone_name() 60 return "DATE_TRUNC('%s', %s)" % (lookup_type, field_sql) 36 61 37 62 def deferrable_sql(self): 38 63 return " DEFERRABLE INITIALLY DEFERRED" -
django/db/backends/sqlite3/base.py
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index 0b19442..421d883 100644
a b class DatabaseOperations(BaseDatabaseOperations): 127 127 # single quotes are used because this is a string (and could otherwise 128 128 # cause a collision with a field name). 129 129 return "django_date_trunc('%s', %s)" % (lookup_type.lower(), field_name) 130 131 def year_lookup_bounds(self, value): 132 """ 133 Returns a two-elements list with the lower and upper bound to be used 134 with a BETWEEN operator to query a field value using a year lookup 135 136 `value` is an int, containing the looked-up year. 137 """ 138 tz = timezone.get_current_timezone() if settings.USE_TZ else None 139 first_dt = datetime.datetime(year=value, month=01, day=01, tzinfo=tz) 140 second_dt = datetime.datetime(year=value, month=12, day=31, hour=23, 141 minute=59, second=59, microsecond=999999, 142 tzinfo=tz) 143 if settings.USE_TZ: 144 first_dt = first_dt.astimezone(timezone.utc) 145 second_dt = second_dt.astimezone(timezone.utc) 146 first = first_dt.strftime('%Y-%m-%d') 147 second = second_dt.strftime('%Y-%m-%d %H:%M:%S.%f') 148 return [first, second] 130 149 131 150 def drop_foreignkey_sql(self): 132 151 return "" … … class DatabaseOperations(BaseDatabaseOperations): 178 197 179 198 return unicode(value) 180 199 181 def year_lookup_bounds(self, value):182 first = '%s-01-01'183 second = '%s-12-31 23:59:59.999999'184 return [first % value, second % value]185 186 200 def convert_values(self, value, field): 187 201 """SQLite returns floats when it should be returning decimals, 188 202 and gets dates and datetimes wrong. … … def _sqlite_extract(lookup_type, dt): 359 373 dt = util.typecast_timestamp(dt) 360 374 except (ValueError, TypeError): 361 375 return None 376 if settings.USE_TZ: 377 tz = timezone.get_current_timezone() 378 dt = dt.astimezone(tz) 362 379 if lookup_type == 'week_day': 363 380 return (dt.isoweekday() % 7) + 1 364 381 else: … … def _sqlite_date_trunc(lookup_type, dt): 369 386 dt = util.typecast_timestamp(dt) 370 387 except (ValueError, TypeError): 371 388 return None 389 if settings.USE_TZ: 390 tz = timezone.get_current_timezone() 391 dt = dt.astimezone(tz) 372 392 if lookup_type == 'year': 373 393 return "%i-01-01 00:00:00" % dt.year 374 394 elif lookup_type == 'month': -
tests/modeltests/timezones/tests.py
diff --git a/tests/modeltests/timezones/tests.py b/tests/modeltests/timezones/tests.py index a8d2c0c..81642df 100644
a b LegacyDatabaseTests = override_settings(USE_TZ=False)(LegacyDatabaseTests) 277 277 278 278 #@override_settings(USE_TZ=True) 279 279 class NewDatabaseTests(BaseDateTimeTests): 280 @requires_tz_support 281 def test_day_in_current_tz(self): 282 dt = datetime.datetime(2012, 03, 05, 01, 00, 00) 283 dt = dt.replace(tzinfo=EAT) 284 Event.objects.create(dt=dt) 285 with timezone.override(UTC): 286 self.assertEqual(Event.objects.dates('dt', 'day')[0].day, 4) 287 with timezone.override(EAT): 288 self.assertEqual(Event.objects.dates('dt', 'day')[0].day, 5) 280 289 281 290 @requires_tz_support 282 291 @skipIf(sys.version_info < (2, 6), "this test requires Python >= 2.6") … … class NewDatabaseTests(BaseDateTimeTests): 427 436 # implementation is changed to perform the aggregation is local time. 428 437 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=EAT)) 429 438 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0, tzinfo=EAT)) 430 self.assertEqual(Event.objects.filter(dt__year=2011).count(), 1) 431 self.assertEqual(Event.objects.filter(dt__month=1).count(), 1) 432 self.assertEqual(Event.objects.filter(dt__day=1).count(), 1) 433 self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 1) 439 with timezone.override(EAT): 440 self.assertEqual(Event.objects.filter(dt__year=2011).count(), 2) 441 self.assertEqual(Event.objects.filter(dt__month=1).count(), 2) 442 self.assertEqual(Event.objects.filter(dt__day=1).count(), 2) 443 self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 2) 444 with timezone.override(UTC): 445 self.assertEqual(Event.objects.filter(dt__year=2011).count(), 1) 446 self.assertEqual(Event.objects.filter(dt__month=1).count(), 1) 447 self.assertEqual(Event.objects.filter(dt__day=1).count(), 1) 448 self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 1) 434 449 435 450 def test_query_aggregation(self): 436 451 # Only min and max make sense for datetimes. … … class NewDatabaseTests(BaseDateTimeTests): 469 484 # Same comment as in test_query_date_related_filters. 470 485 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=EAT)) 471 486 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0, tzinfo=EAT)) 472 self.assertQuerysetEqual(Event.objects.dates('dt', 'year'), 473 [datetime.datetime(2010, 1, 1, tzinfo=UTC), 474 datetime.datetime(2011, 1, 1, tzinfo=UTC)], 475 transform=lambda d: d) 476 self.assertQuerysetEqual(Event.objects.dates('dt', 'month'), 477 [datetime.datetime(2010, 12, 1, tzinfo=UTC), 478 datetime.datetime(2011, 1, 1, tzinfo=UTC)], 479 transform=lambda d: d) 480 self.assertQuerysetEqual(Event.objects.dates('dt', 'day'), 481 [datetime.datetime(2010, 12, 31, tzinfo=UTC), 482 datetime.datetime(2011, 1, 1, tzinfo=UTC)], 483 transform=lambda d: d) 487 with timezone.override(EAT): 488 self.assertQuerysetEqual(Event.objects.dates('dt', 'year'), 489 [datetime.datetime(2011, 1, 1, tzinfo=UTC)], 490 transform=lambda d: d) 491 self.assertQuerysetEqual(Event.objects.dates('dt', 'month'), 492 [datetime.datetime(2011, 1, 1, tzinfo=UTC)], 493 transform=lambda d: d) 494 self.assertQuerysetEqual(Event.objects.dates('dt', 'day'), 495 [datetime.datetime(2011, 1, 1, tzinfo=UTC)], 496 transform=lambda d: d) 497 with timezone.override(UTC): 498 self.assertQuerysetEqual(Event.objects.dates('dt', 'year'), 499 [datetime.datetime(2010, 1, 1, tzinfo=UTC), 500 datetime.datetime(2011, 1, 1, tzinfo=UTC)], 501 transform=lambda d: d) 502 self.assertQuerysetEqual(Event.objects.dates('dt', 'month'), 503 [datetime.datetime(2010, 12, 1, tzinfo=UTC), 504 datetime.datetime(2011, 1, 1, tzinfo=UTC)], 505 transform=lambda d: d) 506 self.assertQuerysetEqual(Event.objects.dates('dt', 'day'), 507 [datetime.datetime(2010, 12, 31, tzinfo=UTC), 508 datetime.datetime(2011, 1, 1, tzinfo=UTC)], 509 transform=lambda d: d) 484 510 485 511 def test_raw_sql(self): 486 512 # Regression test for #17755