Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #17263 -- Added a warning when a naive datetime reaches the dat…

…abase layer while time zone support is enabled.

After this commit, timezones.AdminTests will raise warnings because the sessions contrib app hasn't been upgraded to support time zones yet.
This will be fixed in an upcoming commit.



git-svn-id: http://code.djangoproject.com/svn/django/trunk@17117 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 9c30d48b45cfe694233a9e636bb516bdd9200da9 1 parent 9b8e211
Aymeric Augustin authored November 19, 2011
4  django/db/models/fields/__init__.py
@@ -2,6 +2,7 @@
2 2
 import datetime
3 3
 import decimal
4 4
 import math
  5
+import warnings
5 6
 from itertools import tee
6 7
 
7 8
 from django.db import connection
@@ -789,6 +790,9 @@ def get_prep_value(self, value):
789 790
             # For backwards compatibility, interpret naive datetimes in local
790 791
             # time. This won't work during DST change, but we can't do much
791 792
             # about it, so we let the exceptions percolate up the call stack.
  793
+            warnings.warn(u"DateTimeField received a naive datetime (%s)"
  794
+                          u" while time zone support is active." % value,
  795
+                          RuntimeWarning)
792 796
             default_timezone = timezone.get_default_timezone()
793 797
             value = timezone.make_aware(value, default_timezone)
794 798
         return value
19  docs/topics/i18n/timezones.txt
@@ -106,9 +106,9 @@ Interpretation of naive datetime objects
106 106
 ----------------------------------------
107 107
 
108 108
 When :setting:`USE_TZ` is ``True``, Django still accepts naive datetime
109  
-objects, in order to preserve backwards-compatibility. It attempts to make them
110  
-aware by interpreting them in the :ref:`default time zone
111  
-<default-current-time-zone>`.
  109
+objects, in order to preserve backwards-compatibility. When the database layer
  110
+receives one, it attempts to make it aware by interpreting it in the
  111
+:ref:`default time zone <default-current-time-zone>` and raises a warning.
112 112
 
113 113
 Unfortunately, during DST transitions, some datetimes don't exist or are
114 114
 ambiguous. In such situations, pytz_ raises an exception. Other
@@ -421,11 +421,22 @@ with a naive datetime that you've created in your code.
421 421
 So the second step is to refactor your code wherever you instanciate datetime
422 422
 objects to make them aware. This can be done incrementally.
423 423
 :mod:`django.utils.timezone` defines some handy helpers for compatibility
424  
-code: :func:`~django.utils.timezone.is_aware`,
  424
+code: :func:`~django.utils.timezone.now`,
  425
+:func:`~django.utils.timezone.is_aware`,
425 426
 :func:`~django.utils.timezone.is_naive`,
426 427
 :func:`~django.utils.timezone.make_aware`, and
427 428
 :func:`~django.utils.timezone.make_naive`.
428 429
 
  430
+Finally, in order to help you locate code that needs upgrading, Django raises
  431
+a warning when you attempt to save a naive datetime to the database. During
  432
+development, you can turn such warnings into exceptions and get a traceback
  433
+by adding to your settings file::
  434
+
  435
+    import warnings
  436
+    warnings.filterwarnings(
  437
+            'error', r"DateTimeField received a naive datetime",
  438
+            RuntimeWarning, r'django\.db\.models\.fields')
  439
+
429 440
 .. _pytz: http://pytz.sourceforge.net/
430 441
 .. _these issues: http://pytz.sourceforge.net/#problems-with-localtime
431 442
 .. _tz database: http://en.wikipedia.org/wiki/Tz_database
6  tests/modeltests/timezones/fixtures/users.xml → tests/modeltests/timezones/fixtures/tz_users.xml
@@ -9,9 +9,9 @@
9 9
         <field type="BooleanField" name="is_staff">True</field>
10 10
         <field type="BooleanField" name="is_active">True</field>
11 11
         <field type="BooleanField" name="is_superuser">True</field>
12  
-        <field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field>
13  
-        <field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field>
  12
+        <field type="DateTimeField" name="last_login">2001-01-01 00:00:00+00:00</field>
  13
+        <field type="DateTimeField" name="date_joined">2001-01-01 00:00:00+00:00</field>
14 14
         <field to="auth.group" name="groups" rel="ManyToManyRel"></field>
15 15
         <field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field>
16 16
     </object>
17  
-</django-objects>
  17
+</django-objects>
23  tests/modeltests/timezones/tests.py
@@ -3,6 +3,7 @@
3 3
 import datetime
4 4
 import os
5 5
 import time
  6
+import warnings
6 7
 
7 8
 try:
8 9
     import pytz
@@ -238,7 +239,11 @@ class NewDatabaseTests(BaseDateTimeTests):
238 239
 
239 240
     def test_naive_datetime(self):
240 241
         dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
241  
-        Event.objects.create(dt=dt)
  242
+        with warnings.catch_warnings(record=True) as recorded:
  243
+            Event.objects.create(dt=dt)
  244
+            self.assertEqual(len(recorded), 1)
  245
+            msg = str(recorded[0].message)
  246
+            self.assertTrue(msg.startswith("DateTimeField received a naive datetime"))
242 247
         event = Event.objects.get()
243 248
         # naive datetimes are interpreted in local time
244 249
         self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
@@ -246,7 +251,11 @@ def test_naive_datetime(self):
246 251
     @skipUnlessDBFeature('supports_microsecond_precision')
247 252
     def test_naive_datetime_with_microsecond(self):
248 253
         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
249  
-        Event.objects.create(dt=dt)
  254
+        with warnings.catch_warnings(record=True) as recorded:
  255
+            Event.objects.create(dt=dt)
  256
+            self.assertEqual(len(recorded), 1)
  257
+            msg = str(recorded[0].message)
  258
+            self.assertTrue(msg.startswith("DateTimeField received a naive datetime"))
250 259
         event = Event.objects.get()
251 260
         # naive datetimes are interpreted in local time
252 261
         self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
@@ -254,7 +263,11 @@ def test_naive_datetime_with_microsecond(self):
254 263
     @skipIfDBFeature('supports_microsecond_precision')
255 264
     def test_naive_datetime_with_microsecond_unsupported(self):
256 265
         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
257  
-        Event.objects.create(dt=dt)
  266
+        with warnings.catch_warnings(record=True) as recorded:
  267
+            Event.objects.create(dt=dt)
  268
+            self.assertEqual(len(recorded), 1)
  269
+            msg = str(recorded[0].message)
  270
+            self.assertTrue(msg.startswith("DateTimeField received a naive datetime"))
258 271
         event = Event.objects.get()
259 272
         # microseconds are lost during a round-trip in the database
260 273
         # naive datetimes are interpreted in local time
@@ -294,7 +307,7 @@ def test_aware_datetime_in_other_timezone(self):
294 307
         self.assertEqual(event.dt, dt)
295 308
 
296 309
     def test_auto_now_and_auto_now_add(self):
297  
-        now = datetime.datetime.utcnow().replace(tzinfo=UTC)
  310
+        now = timezone.now()
298 311
         past = now - datetime.timedelta(seconds=2)
299 312
         future = now + datetime.timedelta(seconds=2)
300 313
         Timestamp.objects.create()
@@ -824,7 +837,7 @@ def test_model_form(self):
824 837
 class AdminTests(BaseDateTimeTests):
825 838
 
826 839
     urls = 'modeltests.timezones.urls'
827  
-    fixtures = ['users.xml']
  840
+    fixtures = ['tz_users.xml']
828 841
 
829 842
     def setUp(self):
830 843
         self.client.login(username='super', password='secret')

0 notes on commit 9c30d48

Please sign in to comment.
Something went wrong with that request. Please try again.