Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Added support for time zones. Thanks Luke Plant for the review. Fixed…

… #2626.

For more information on this project, see this thread:
http://groups.google.com/group/django-developers/browse_thread/thread/cf0423bbb85b1bbf



git-svn-id: http://code.djangoproject.com/svn/django/trunk@17106 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 9b1cb755a28f020e27d4268c214b25315d4de42e 1 parent 01f7034
Aymeric Augustin authored November 18, 2011

Showing 58 changed files with 2,719 additions and 283 deletions. Show diff stats Hide diff stats

  1. 9  django/conf/global_settings.py
  2. 5  django/conf/project_template/project_name/settings.py
  3. 3  django/contrib/admin/util.py
  4. 18  django/contrib/humanize/templatetags/humanize.py
  5. 72  django/contrib/humanize/tests.py
  6. 3  django/contrib/syndication/views.py
  7. 5  django/core/context_processors.py
  8. 25  django/core/serializers/json.py
  9. 3  django/db/backends/__init__.py
  10. 27  django/db/backends/mysql/base.py
  11. 45  django/db/backends/oracle/base.py
  12. 17  django/db/backends/postgresql_psycopg2/base.py
  13. 56  django/db/backends/sqlite3/base.py
  14. 6  django/db/backends/util.py
  15. 168  django/db/models/fields/__init__.py
  16. 2  django/db/utils.py
  17. 18  django/forms/fields.py
  18. 31  django/forms/util.py
  19. 3  django/forms/widgets.py
  20. 7  django/template/base.py
  21. 12  django/template/context.py
  22. 2  django/template/debug.py
  23. 4  django/template/defaultfilters.py
  24. 191  django/templatetags/tz.py
  25. 5  django/utils/cache.py
  26. 14  django/utils/dateformat.py
  27. 93  django/utils/dateparse.py
  28. 5  django/utils/feedgenerator.py
  29. 16  django/utils/timesince.py
  30. 266  django/utils/timezone.py
  31. 19  django/utils/tzinfo.py
  32. 25  docs/howto/custom-template-tags.txt
  33. 13  docs/ref/models/querysets.txt
  34. 54  docs/ref/settings.txt
  35. 63  docs/ref/templates/builtins.txt
  36. 125  docs/ref/utils.txt
  37. 53  docs/releases/1.4.txt
  38. 4  docs/topics/cache.txt
  39. 10  docs/topics/i18n/index.txt
  40. 429  docs/topics/i18n/timezones.txt
  41. 22  tests/modeltests/fixtures/tests.py
  42. 6  tests/modeltests/serializers/tests.py
  43. 0  tests/modeltests/timezones/__init__.py
  44. 15  tests/modeltests/timezones/admin.py
  45. 17  tests/modeltests/timezones/fixtures/users.xml
  46. 13  tests/modeltests/timezones/forms.py
  47. 8  tests/modeltests/timezones/models.py
  48. 871  tests/modeltests/timezones/tests.py
  49. 10  tests/modeltests/timezones/urls.py
  50. 43  tests/modeltests/validation/test_error_messages.py
  51. 18  tests/regressiontests/cache/tests.py
  52. 4  tests/regressiontests/datatypes/tests.py
  53. 2  tests/regressiontests/defaultfilters/tests.py
  54. 2  tests/regressiontests/utils/dateformat.py
  55. 1  tests/regressiontests/utils/tests.py
  56. 9  tests/regressiontests/utils/timesince.py
  57. 18  tests/regressiontests/utils/timezone.py
  58. 17  tests/regressiontests/utils/tzinfo.py
9  django/conf/global_settings.py
@@ -31,9 +31,13 @@
31 31
 
32 32
 # Local time zone for this installation. All choices can be found here:
33 33
 # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name (although not all
34  
-# systems may support all possibilities).
  34
+# systems may support all possibilities). When USE_TZ is True, this is
  35
+# interpreted as the default user time zone.
35 36
 TIME_ZONE = 'America/Chicago'
36 37
 
  38
+# If you set this to True, Django will use timezone-aware datetimes.
  39
+USE_TZ = False
  40
+
37 41
 # Language code for this installation. All choices can be found here:
38 42
 # http://www.i18nguy.com/unicode/language-identifiers.html
39 43
 LANGUAGE_CODE = 'en-us'
@@ -119,7 +123,7 @@
119 123
 LANGUAGE_COOKIE_NAME = 'django_language'
120 124
 
121 125
 # If you set this to True, Django will format dates, numbers and calendars
122  
-# according to user current locale
  126
+# according to user current locale.
123 127
 USE_L10N = False
124 128
 
125 129
 # Not-necessarily-technical managers of the site. They get broken link
@@ -192,6 +196,7 @@
192 196
     'django.core.context_processors.i18n',
193 197
     'django.core.context_processors.media',
194 198
     'django.core.context_processors.static',
  199
+    'django.core.context_processors.tz',
195 200
 #    'django.core.context_processors.request',
196 201
     'django.contrib.messages.context_processors.messages',
197 202
 )
5  django/conf/project_template/project_name/settings.py
@@ -40,9 +40,12 @@
40 40
 USE_I18N = True
41 41
 
42 42
 # If you set this to False, Django will not format dates, numbers and
43  
-# calendars according to the current locale
  43
+# calendars according to the current locale.
44 44
 USE_L10N = True
45 45
 
  46
+# If you set this to False, Django will not use timezone-aware datetimes.
  47
+USE_TZ = True
  48
+
46 49
 # Absolute filesystem path to the directory that will hold user-uploaded files.
47 50
 # Example: "/home/media/media.lawrence.com/media/"
48 51
 MEDIA_ROOT = ''
3  django/contrib/admin/util.py
@@ -7,6 +7,7 @@
7 7
 from django.utils.html import escape
8 8
 from django.utils.safestring import mark_safe
9 9
 from django.utils.text import capfirst
  10
+from django.utils import timezone
10 11
 from django.utils.encoding import force_unicode, smart_unicode, smart_str
11 12
 from django.utils.translation import ungettext
12 13
 from django.core.urlresolvers import reverse
@@ -293,6 +294,8 @@ def display_for_field(value, field):
293 294
         return _boolean_icon(value)
294 295
     elif value is None:
295 296
         return EMPTY_CHANGELIST_VALUE
  297
+    elif isinstance(field, models.DateTimeField):
  298
+        return formats.localize(timezone.aslocaltime(value))
296 299
     elif isinstance(field, models.DateField) or isinstance(field, models.TimeField):
297 300
         return formats.localize(value)
298 301
     elif isinstance(field, models.DecimalField):
18  django/contrib/humanize/templatetags/humanize.py
@@ -7,7 +7,7 @@
7 7
 from django.utils.encoding import force_unicode
8 8
 from django.utils.formats import number_format
9 9
 from django.utils.translation import pgettext, ungettext, ugettext as _
10  
-from django.utils.tzinfo import LocalTimezone
  10
+from django.utils.timezone import is_aware, utc
11 11
 
12 12
 register = template.Library()
13 13
 
@@ -158,8 +158,8 @@ def naturalday(value, arg=None):
158 158
     except ValueError:
159 159
         # Date arguments out of range
160 160
         return value
161  
-    today = datetime.now(tzinfo).replace(microsecond=0, second=0, minute=0, hour=0)
162  
-    delta = value - today.date()
  161
+    today = datetime.now(tzinfo).date()
  162
+    delta = value - today
163 163
     if delta.days == 0:
164 164
         return _(u'today')
165 165
     elif delta.days == 1:
@@ -174,18 +174,10 @@ def naturaltime(value):
174 174
     For date and time values shows how many seconds, minutes or hours ago
175 175
     compared to current timestamp returns representing string.
176 176
     """
177  
-    try:
178  
-        value = datetime(value.year, value.month, value.day, value.hour, value.minute, value.second)
179  
-    except AttributeError:
180  
-        return value
181  
-    except ValueError:
  177
+    if not isinstance(value, date): # datetime is a subclass of date
182 178
         return value
183 179
 
184  
-    if getattr(value, 'tzinfo', None):
185  
-        now = datetime.now(LocalTimezone(value))
186  
-    else:
187  
-        now = datetime.now()
188  
-    now = now - timedelta(0, 0, now.microsecond)
  180
+    now = datetime.now(utc if is_aware(value) else None)
189 181
     if value < now:
190 182
         delta = now - value
191 183
         if delta.days != 0:
72  django/contrib/humanize/tests.py
... ...
@@ -1,11 +1,12 @@
1 1
 from __future__ import with_statement
2  
-from datetime import timedelta, date, datetime
  2
+import datetime
3 3
 
4 4
 from django.template import Template, Context, defaultfilters
5 5
 from django.test import TestCase
6 6
 from django.utils import translation, tzinfo
7 7
 from django.utils.translation import ugettext as _
8 8
 from django.utils.html import escape
  9
+from django.utils.timezone import utc
9 10
 
10 11
 
11 12
 class HumanizeTests(TestCase):
@@ -88,10 +89,10 @@ def test_apnumber(self):
88 89
         self.humanize_tester(test_list, result_list, 'apnumber')
89 90
 
90 91
     def test_naturalday(self):
91  
-        today = date.today()
92  
-        yesterday = today - timedelta(days=1)
93  
-        tomorrow = today + timedelta(days=1)
94  
-        someday = today - timedelta(days=10)
  92
+        today = datetime.date.today()
  93
+        yesterday = today - datetime.timedelta(days=1)
  94
+        tomorrow = today + datetime.timedelta(days=1)
  95
+        someday = today - datetime.timedelta(days=10)
95 96
         notdate = u"I'm not a date value"
96 97
 
97 98
         test_list = (today, yesterday, tomorrow, someday, notdate, None)
@@ -103,41 +104,46 @@ def test_naturalday(self):
103 104
     def test_naturalday_tz(self):
104 105
         from django.contrib.humanize.templatetags.humanize import naturalday
105 106
 
106  
-        today = date.today()
107  
-        tz_one = tzinfo.FixedOffset(timedelta(hours=-12))
108  
-        tz_two = tzinfo.FixedOffset(timedelta(hours=12))
  107
+        today = datetime.date.today()
  108
+        tz_one = tzinfo.FixedOffset(datetime.timedelta(hours=-12))
  109
+        tz_two = tzinfo.FixedOffset(datetime.timedelta(hours=12))
109 110
 
110 111
         # Can be today or yesterday
111  
-        date_one = datetime(today.year, today.month, today.day, tzinfo=tz_one)
  112
+        date_one = datetime.datetime(today.year, today.month, today.day, tzinfo=tz_one)
112 113
         naturalday_one = naturalday(date_one)
113 114
         # Can be today or tomorrow
114  
-        date_two = datetime(today.year, today.month, today.day, tzinfo=tz_two)
  115
+        date_two = datetime.datetime(today.year, today.month, today.day, tzinfo=tz_two)
115 116
         naturalday_two = naturalday(date_two)
116 117
 
117 118
         # As 24h of difference they will never be the same
118 119
         self.assertNotEqual(naturalday_one, naturalday_two)
119 120
 
120 121
     def test_naturaltime(self):
  122
+        class naive(datetime.tzinfo):
  123
+            def utcoffset(self, dt):
  124
+                return None
121 125
         # we're going to mock datetime.datetime, so use a fixed datetime
122  
-        now = datetime(2011, 8, 15)
  126
+        now = datetime.datetime(2011, 8, 15)
123 127
         test_list = [
124 128
             now,
125  
-            now - timedelta(seconds=1),
126  
-            now - timedelta(seconds=30),
127  
-            now - timedelta(minutes=1, seconds=30),
128  
-            now - timedelta(minutes=2),
129  
-            now - timedelta(hours=1, minutes=30, seconds=30),
130  
-            now - timedelta(hours=23, minutes=50, seconds=50),
131  
-            now - timedelta(days=1),
132  
-            now - timedelta(days=500),
133  
-            now + timedelta(seconds=1),
134  
-            now + timedelta(seconds=30),
135  
-            now + timedelta(minutes=1, seconds=30),
136  
-            now + timedelta(minutes=2),
137  
-            now + timedelta(hours=1, minutes=30, seconds=30),
138  
-            now + timedelta(hours=23, minutes=50, seconds=50),
139  
-            now + timedelta(days=1),
140  
-            now + timedelta(days=500),
  129
+            now - datetime.timedelta(seconds=1),
  130
+            now - datetime.timedelta(seconds=30),
  131
+            now - datetime.timedelta(minutes=1, seconds=30),
  132
+            now - datetime.timedelta(minutes=2),
  133
+            now - datetime.timedelta(hours=1, minutes=30, seconds=30),
  134
+            now - datetime.timedelta(hours=23, minutes=50, seconds=50),
  135
+            now - datetime.timedelta(days=1),
  136
+            now - datetime.timedelta(days=500),
  137
+            now + datetime.timedelta(seconds=1),
  138
+            now + datetime.timedelta(seconds=30),
  139
+            now + datetime.timedelta(minutes=1, seconds=30),
  140
+            now + datetime.timedelta(minutes=2),
  141
+            now + datetime.timedelta(hours=1, minutes=30, seconds=30),
  142
+            now + datetime.timedelta(hours=23, minutes=50, seconds=50),
  143
+            now + datetime.timedelta(days=1),
  144
+            now + datetime.timedelta(days=500),
  145
+            now.replace(tzinfo=naive()),
  146
+            now.replace(tzinfo=utc),
141 147
         ]
142 148
         result_list = [
143 149
             'now',
@@ -157,14 +163,20 @@ def test_naturaltime(self):
157 163
             '23 hours from now',
158 164
             '1 day from now',
159 165
             '1 year, 4 months from now',
  166
+            'now',
  167
+            'now',
160 168
         ]
161 169
 
162 170
         # mock out datetime so these tests don't fail occasionally when the
163 171
         # test runs too slow
164  
-        class MockDateTime(datetime):
  172
+        class MockDateTime(datetime.datetime):
165 173
             @classmethod
166  
-            def now(self):
167  
-                return now
  174
+            def now(self, tz=None):
  175
+                if tz is None or tz.utcoffset(now) is None:
  176
+                    return now
  177
+                else:
  178
+                    # equals now.replace(tzinfo=utc)
  179
+                    return now.replace(tzinfo=tz) + tz.utcoffset(now)
168 180
 
169 181
         # naturaltime also calls timesince/timeuntil
170 182
         from django.contrib.humanize.templatetags import humanize
3  django/contrib/syndication/views.py
@@ -6,6 +6,7 @@
6 6
 from django.utils import feedgenerator, tzinfo
7 7
 from django.utils.encoding import force_unicode, iri_to_uri, smart_unicode
8 8
 from django.utils.html import escape
  9
+from django.utils.timezone import is_naive
9 10
 
10 11
 def add_domain(domain, url, secure=False):
11 12
     if not (url.startswith('http://')
@@ -164,7 +165,7 @@ def get_feed(self, obj, request):
164 165
                 author_email = author_link = None
165 166
 
166 167
             pubdate = self.__get_dynamic_attr('item_pubdate', item)
167  
-            if pubdate and not pubdate.tzinfo:
  168
+            if pubdate and is_naive(pubdate):
168 169
                 ltz = tzinfo.LocalTimezone(pubdate)
169 170
                 pubdate = pubdate.replace(tzinfo=ltz)
170 171
 
5  django/core/context_processors.py
@@ -48,6 +48,11 @@ def i18n(request):
48 48
 
49 49
     return context_extras
50 50
 
  51
+def tz(request):
  52
+    from django.utils import timezone
  53
+
  54
+    return {'TIME_ZONE': timezone.get_current_timezone_name()}
  55
+
51 56
 def static(request):
52 57
     """
53 58
     Adds static-related context variables to the context.
25  django/core/serializers/json.py
@@ -8,8 +8,8 @@
8 8
 
9 9
 from django.core.serializers.python import Serializer as PythonSerializer
10 10
 from django.core.serializers.python import Deserializer as PythonDeserializer
11  
-from django.utils import datetime_safe
12 11
 from django.utils import simplejson
  12
+from django.utils.timezone import is_aware
13 13
 
14 14
 class Serializer(PythonSerializer):
15 15
     """
@@ -39,19 +39,24 @@ class DjangoJSONEncoder(simplejson.JSONEncoder):
39 39
     """
40 40
     JSONEncoder subclass that knows how to encode date/time and decimal types.
41 41
     """
42  
-
43  
-    DATE_FORMAT = "%Y-%m-%d"
44  
-    TIME_FORMAT = "%H:%M:%S"
45  
-
46 42
     def default(self, o):
  43
+        # See "Date Time String Format" in the ECMA-262 specification.
47 44
         if isinstance(o, datetime.datetime):
48  
-            d = datetime_safe.new_datetime(o)
49  
-            return d.strftime("%s %s" % (self.DATE_FORMAT, self.TIME_FORMAT))
  45
+            r = o.isoformat()
  46
+            if o.microsecond:
  47
+                r = r[:23] + r[26:]
  48
+            if r.endswith('+00:00'):
  49
+                r = r[:-6] + 'Z'
  50
+            return r
50 51
         elif isinstance(o, datetime.date):
51  
-            d = datetime_safe.new_date(o)
52  
-            return d.strftime(self.DATE_FORMAT)
  52
+            return o.isoformat()
53 53
         elif isinstance(o, datetime.time):
54  
-            return o.strftime(self.TIME_FORMAT)
  54
+            if is_aware(o):
  55
+                raise ValueError("JSON can't represent timezone-aware times.")
  56
+            r = o.isoformat()
  57
+            if o.microsecond:
  58
+                r = r[:12]
  59
+            return r
55 60
         elif isinstance(o, decimal.Decimal):
56 61
             return str(o)
57 62
         else:
3  django/db/backends/__init__.py
@@ -10,6 +10,7 @@
10 10
 from django.db.backends import util
11 11
 from django.db.transaction import TransactionManagementError
12 12
 from django.utils.importlib import import_module
  13
+from django.utils.timezone import is_aware
13 14
 
14 15
 
15 16
 class BaseDatabaseWrapper(local):
@@ -743,6 +744,8 @@ def value_to_db_time(self, value):
743 744
         """
744 745
         if value is None:
745 746
             return None
  747
+        if is_aware(value):
  748
+            raise ValueError("Django does not support timezone-aware times.")
746 749
         return unicode(value)
747 750
 
748 751
     def value_to_db_decimal(self, value, max_digits, decimal_places):
27  django/db/backends/mysql/base.py
@@ -33,6 +33,7 @@
33 33
 from django.db.backends.mysql.introspection import DatabaseIntrospection
34 34
 from django.db.backends.mysql.validation import DatabaseValidation
35 35
 from django.utils.safestring import SafeString, SafeUnicode
  36
+from django.utils.timezone import is_aware, is_naive, utc
36 37
 
37 38
 # Raise exceptions for database warnings if DEBUG is on
38 39
 from django.conf import settings
@@ -43,16 +44,29 @@
43 44
 DatabaseError = Database.DatabaseError
44 45
 IntegrityError = Database.IntegrityError
45 46
 
  47
+# It's impossible to import datetime_or_None directly from MySQLdb.times
  48
+datetime_or_None = conversions[FIELD_TYPE.DATETIME]
  49
+
  50
+def datetime_or_None_with_timezone_support(value):
  51
+    dt = datetime_or_None(value)
  52
+    # Confirm that dt is naive before overwriting its tzinfo.
  53
+    if dt is not None and settings.USE_TZ and is_naive(dt):
  54
+        dt = dt.replace(tzinfo=utc)
  55
+    return dt
  56
+
46 57
 # MySQLdb-1.2.1 returns TIME columns as timedelta -- they are more like
47 58
 # timedelta in terms of actual behavior as they are signed and include days --
48 59
 # and Django expects time, so we still need to override that. We also need to
49 60
 # add special handling for SafeUnicode and SafeString as MySQLdb's type
50 61
 # checking is too tight to catch those (see Django ticket #6052).
  62
+# Finally, MySQLdb always returns naive datetime objects. However, when
  63
+# timezone support is active, Django expects timezone-aware datetime objects.
51 64
 django_conversions = conversions.copy()
52 65
 django_conversions.update({
53 66
     FIELD_TYPE.TIME: util.typecast_time,
54 67
     FIELD_TYPE.DECIMAL: util.typecast_decimal,
55 68
     FIELD_TYPE.NEWDECIMAL: util.typecast_decimal,
  69
+    FIELD_TYPE.DATETIME: datetime_or_None_with_timezone_support,
56 70
 })
57 71
 
58 72
 # This should match the numerical portion of the version numbers (we can treat
@@ -238,8 +252,11 @@ def value_to_db_datetime(self, value):
238 252
             return None
239 253
 
240 254
         # MySQL doesn't support tz-aware datetimes
241  
-        if value.tzinfo is not None:
242  
-            raise ValueError("MySQL backend does not support timezone-aware datetimes.")
  255
+        if is_aware(value):
  256
+            if settings.USE_TZ:
  257
+                value = value.astimezone(utc).replace(tzinfo=None)
  258
+            else:
  259
+                raise ValueError("MySQL backend does not support timezone-aware datetimes when USE_TZ is False.")
243 260
 
244 261
         # MySQL doesn't support microseconds
245 262
         return unicode(value.replace(microsecond=0))
@@ -248,9 +265,9 @@ def value_to_db_time(self, value):
248 265
         if value is None:
249 266
             return None
250 267
 
251  
-        # MySQL doesn't support tz-aware datetimes
252  
-        if value.tzinfo is not None:
253  
-            raise ValueError("MySQL backend does not support timezone-aware datetimes.")
  268
+        # MySQL doesn't support tz-aware times
  269
+        if is_aware(value):
  270
+            raise ValueError("MySQL backend does not support timezone-aware times.")
254 271
 
255 272
         # MySQL doesn't support microseconds
256 273
         return unicode(value.replace(microsecond=0))
45  django/db/backends/oracle/base.py
@@ -44,6 +44,7 @@ def _setup_environment(environ):
44 44
     from django.core.exceptions import ImproperlyConfigured
45 45
     raise ImproperlyConfigured("Error loading cx_Oracle module: %s" % e)
46 46
 
  47
+from django.conf import settings
47 48
 from django.db import utils
48 49
 from django.db.backends import *
49 50
 from django.db.backends.signals import connection_created
@@ -51,6 +52,7 @@ def _setup_environment(environ):
51 52
 from django.db.backends.oracle.creation import DatabaseCreation
52 53
 from django.db.backends.oracle.introspection import DatabaseIntrospection
53 54
 from django.utils.encoding import smart_str, force_unicode
  55
+from django.utils.timezone import is_aware, is_naive, utc
54 56
 
55 57
 DatabaseError = Database.DatabaseError
56 58
 IntegrityError = Database.IntegrityError
@@ -333,11 +335,17 @@ def tablespace_sql(self, tablespace, inline=False):
333 335
             return "TABLESPACE %s" % self.quote_name(tablespace)
334 336
 
335 337
     def value_to_db_datetime(self, value):
  338
+        if value is None:
  339
+            return None
  340
+
336 341
         # Oracle doesn't support tz-aware datetimes
337  
-        if getattr(value, 'tzinfo', None) is not None:
338  
-            raise ValueError("Oracle backend does not support timezone-aware datetimes.")
  342
+        if is_aware(value):
  343
+            if settings.USE_TZ:
  344
+                value = value.astimezone(utc).replace(tzinfo=None)
  345
+            else:
  346
+                raise ValueError("Oracle backend does not support timezone-aware datetimes when USE_TZ is False.")
339 347
 
340  
-        return super(DatabaseOperations, self).value_to_db_datetime(value)
  348
+        return unicode(value)
341 349
 
342 350
     def value_to_db_time(self, value):
343 351
         if value is None:
@@ -346,9 +354,9 @@ def value_to_db_time(self, value):
346 354
         if isinstance(value, basestring):
347 355
             return datetime.datetime.strptime(value, '%H:%M:%S')
348 356
 
349  
-        # Oracle doesn't support tz-aware datetimes
350  
-        if value.tzinfo is not None:
351  
-            raise ValueError("Oracle backend does not support timezone-aware datetimes.")
  357
+        # Oracle doesn't support tz-aware times
  358
+        if is_aware(value):
  359
+            raise ValueError("Oracle backend does not support timezone-aware times.")
352 360
 
353 361
         return datetime.datetime(1900, 1, 1, value.hour, value.minute,
354 362
                                  value.second, value.microsecond)
@@ -472,9 +480,28 @@ def _cursor(self):
472 480
             # Set oracle date to ansi date format.  This only needs to execute
473 481
             # once when we create a new connection. We also set the Territory
474 482
             # to 'AMERICA' which forces Sunday to evaluate to a '1' in TO_CHAR().
475  
-            cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' "
476  
-                           "NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF' "
477  
-                           "NLS_TERRITORY = 'AMERICA'")
  483
+            cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'"
  484
+                           " NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'"
  485
+                           " NLS_TERRITORY = 'AMERICA'"
  486
+                           + (" TIME_ZONE = 'UTC'" if settings.USE_TZ else ''))
  487
+
  488
+            def datetime_converter(dt):
  489
+                # Confirm that dt is naive before overwriting its tzinfo.
  490
+                if dt is not None and is_naive(dt):
  491
+                    dt = dt.replace(tzinfo=utc)
  492
+                return dt
  493
+
  494
+            def output_type_handler(cursor, name, default_type,
  495
+                                    size, precision, scale):
  496
+                # datetimes are returned as TIMESTAMP, except the results
  497
+                # of "dates" queries, which are returned as DATETIME.
  498
+                if settings.USE_TZ and default_type in (Database.TIMESTAMP,
  499
+                                                        Database.DATETIME):
  500
+                    return cursor.var(default_type,
  501
+                                      arraysize=cursor.arraysize,
  502
+                                      outconverter=datetime_converter)
  503
+
  504
+            self.connection.outputtypehandler = output_type_handler
478 505
 
479 506
             if 'operators' not in self.__dict__:
480 507
                 # Ticket #14149: Check whether our LIKE implementation will
17  django/db/backends/postgresql_psycopg2/base.py
@@ -13,8 +13,9 @@
13 13
 from django.db.backends.postgresql_psycopg2.creation import DatabaseCreation
14 14
 from django.db.backends.postgresql_psycopg2.version import get_version
15 15
 from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
16  
-from django.utils.safestring import SafeUnicode, SafeString
17 16
 from django.utils.log import getLogger
  17
+from django.utils.safestring import SafeUnicode, SafeString
  18
+from django.utils.timezone import utc
18 19
 
19 20
 try:
20 21
     import psycopg2 as Database
@@ -32,6 +33,11 @@
32 33
 
33 34
 logger = getLogger('django.db.backends')
34 35
 
  36
+def utc_tzinfo_factory(offset):
  37
+    if offset != 0:
  38
+        raise AssertionError("database connection isn't set to UTC")
  39
+    return utc
  40
+
35 41
 class CursorWrapper(object):
36 42
     """
37 43
     A thin wrapper around psycopg2's normal cursor class so that we can catch
@@ -144,11 +150,9 @@ def _get_pg_version(self):
144 150
 
145 151
     def _cursor(self):
146 152
         new_connection = False
147  
-        set_tz = False
148 153
         settings_dict = self.settings_dict
149 154
         if self.connection is None:
150 155
             new_connection = True
151  
-            set_tz = settings_dict.get('TIME_ZONE')
152 156
             if settings_dict['NAME'] == '':
153 157
                 from django.core.exceptions import ImproperlyConfigured
154 158
                 raise ImproperlyConfigured("You need to specify NAME in your Django settings file.")
@@ -171,10 +175,11 @@ def _cursor(self):
171 175
             self.connection.set_isolation_level(self.isolation_level)
172 176
             connection_created.send(sender=self.__class__, connection=self)
173 177
         cursor = self.connection.cursor()
174  
-        cursor.tzinfo_factory = None
  178
+        cursor.tzinfo_factory = utc_tzinfo_factory if settings.USE_TZ else None
175 179
         if new_connection:
176  
-            if set_tz:
177  
-                cursor.execute("SET TIME ZONE %s", [settings_dict['TIME_ZONE']])
  180
+            tz = 'UTC' if settings.USE_TZ else settings_dict.get('TIME_ZONE')
  181
+            if tz:
  182
+                cursor.execute("SET TIME ZONE %s", [tz])
178 183
             self._get_pg_version()
179 184
         return CursorWrapper(cursor)
180 185
 
56  django/db/backends/sqlite3/base.py
@@ -10,13 +10,16 @@
10 10
 import re
11 11
 import sys
12 12
 
  13
+from django.conf import settings
13 14
 from django.db import utils
14 15
 from django.db.backends import *
15 16
 from django.db.backends.signals import connection_created
16 17
 from django.db.backends.sqlite3.client import DatabaseClient
17 18
 from django.db.backends.sqlite3.creation import DatabaseCreation
18 19
 from django.db.backends.sqlite3.introspection import DatabaseIntrospection
  20
+from django.utils.dateparse import parse_date, parse_datetime, parse_time
19 21
 from django.utils.safestring import SafeString
  22
+from django.utils.timezone import is_aware, is_naive, utc
20 23
 
21 24
 try:
22 25
     try:
@@ -31,22 +34,29 @@
31 34
 DatabaseError = Database.DatabaseError
32 35
 IntegrityError = Database.IntegrityError
33 36
 
  37
+def parse_datetime_with_timezone_support(value):
  38
+    dt = parse_datetime(value)
  39
+    # Confirm that dt is naive before overwriting its tzinfo.
  40
+    if dt is not None and settings.USE_TZ and is_naive(dt):
  41
+        dt = dt.replace(tzinfo=utc)
  42
+    return dt
  43
+
34 44
 Database.register_converter("bool", lambda s: str(s) == '1')
35  
-Database.register_converter("time", util.typecast_time)
36  
-Database.register_converter("date", util.typecast_date)
37  
-Database.register_converter("datetime", util.typecast_timestamp)
38  
-Database.register_converter("timestamp", util.typecast_timestamp)
39  
-Database.register_converter("TIMESTAMP", util.typecast_timestamp)
  45
+Database.register_converter("time", parse_time)
  46
+Database.register_converter("date", parse_date)
  47
+Database.register_converter("datetime", parse_datetime_with_timezone_support)
  48
+Database.register_converter("timestamp", parse_datetime_with_timezone_support)
  49
+Database.register_converter("TIMESTAMP", parse_datetime_with_timezone_support)
40 50
 Database.register_converter("decimal", util.typecast_decimal)
41 51
 Database.register_adapter(decimal.Decimal, util.rev_typecast_decimal)
42  
-if Database.version_info >= (2,4,1):
  52
+if Database.version_info >= (2, 4, 1):
43 53
     # Starting in 2.4.1, the str type is not accepted anymore, therefore,
44 54
     # we convert all str objects to Unicode
45 55
     # As registering a adapter for a primitive type causes a small
46 56
     # slow-down, this adapter is only registered for sqlite3 versions
47 57
     # needing it.
48  
-    Database.register_adapter(str, lambda s:s.decode('utf-8'))
49  
-    Database.register_adapter(SafeString, lambda s:s.decode('utf-8'))
  58
+    Database.register_adapter(str, lambda s: s.decode('utf-8'))
  59
+    Database.register_adapter(SafeString, lambda s: s.decode('utf-8'))
50 60
 
51 61
 class DatabaseFeatures(BaseDatabaseFeatures):
52 62
     # SQLite cannot handle us only partially reading from a cursor's result set
@@ -56,6 +66,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
56 66
     can_use_chunked_reads = False
57 67
     test_db_allows_multiple_connections = False
58 68
     supports_unspecified_pk = True
  69
+    supports_timezones = False
59 70
     supports_1000_query_parameters = False
60 71
     supports_mixed_date_datetime_comparisons = False
61 72
     has_bulk_insert = True
@@ -131,6 +142,29 @@ def sql_flush(self, style, tables, sequences):
131 142
         # sql_flush() implementations). Just return SQL at this point
132 143
         return sql
133 144
 
  145
+    def value_to_db_datetime(self, value):
  146
+        if value is None:
  147
+            return None
  148
+
  149
+        # SQLite doesn't support tz-aware datetimes
  150
+        if is_aware(value):
  151
+            if settings.USE_TZ:
  152
+                value = value.astimezone(utc).replace(tzinfo=None)
  153
+            else:
  154
+                raise ValueError("SQLite backend does not support timezone-aware datetimes when USE_TZ is False.")
  155
+
  156
+        return unicode(value)
  157
+
  158
+    def value_to_db_time(self, value):
  159
+        if value is None:
  160
+            return None
  161
+
  162
+        # SQLite doesn't support tz-aware datetimes
  163
+        if is_aware(value):
  164
+            raise ValueError("SQLite backend does not support timezone-aware times.")
  165
+
  166
+        return unicode(value)
  167
+
134 168
     def year_lookup_bounds(self, value):
135 169
         first = '%s-01-01'
136 170
         second = '%s-12-31 23:59:59.999999'
@@ -147,11 +181,11 @@ def convert_values(self, value, field):
147 181
         elif internal_type and internal_type.endswith('IntegerField') or internal_type == 'AutoField':
148 182
             return int(value)
149 183
         elif internal_type == 'DateField':
150  
-            return util.typecast_date(value)
  184
+            return parse_date(value)
151 185
         elif internal_type == 'DateTimeField':
152  
-            return util.typecast_timestamp(value)
  186
+            return parse_datetime_with_timezone_support(value)
153 187
         elif internal_type == 'TimeField':
154  
-            return util.typecast_time(value)
  188
+            return parse_time(value)
155 189
 
156 190
         # No field, or the field isn't known to be a decimal or integer
157 191
         return value
6  django/db/backends/util.py
@@ -3,7 +3,9 @@
3 3
 import hashlib
4 4
 from time import time
5 5
 
  6
+from django.conf import settings
6 7
 from django.utils.log import getLogger
  8
+from django.utils.timezone import utc
7 9
 
8 10
 
9 11
 logger = getLogger('django.db.backends')
@@ -99,8 +101,10 @@ def typecast_timestamp(s): # does NOT store time zone information
99 101
         seconds, microseconds = seconds.split('.')
100 102
     else:
101 103
         microseconds = '0'
  104
+    tzinfo = utc if settings.USE_TZ else None
102 105
     return datetime.datetime(int(dates[0]), int(dates[1]), int(dates[2]),
103  
-        int(times[0]), int(times[1]), int(seconds), int((microseconds + '000000')[:6]))
  106
+        int(times[0]), int(times[1]), int(seconds),
  107
+        int((microseconds + '000000')[:6]), tzinfo)
104 108
 
105 109
 def typecast_decimal(s):
106 110
     if s is None or s == '':
168  django/db/models/fields/__init__.py
... ...
@@ -1,8 +1,6 @@
1 1
 import copy
2 2
 import datetime
3 3
 import decimal
4  
-import re
5  
-import time
6 4
 import math
7 5
 from itertools import tee
8 6
 
@@ -12,8 +10,10 @@
12 10
 from django import forms
13 11
 from django.core import exceptions, validators
14 12
 from django.utils.datastructures import DictWrapper
  13
+from django.utils.dateparse import parse_date, parse_datetime, parse_time
15 14
 from django.utils.functional import curry
16 15
 from django.utils.text import capfirst
  16
+from django.utils import timezone
17 17
 from django.utils.translation import ugettext_lazy as _
18 18
 from django.utils.encoding import smart_unicode, force_unicode, smart_str
19 19
 from django.utils.ipv6 import clean_ipv6_address
@@ -180,8 +180,8 @@ def validate(self, value, model_instance):
180 180
                             return
181 181
                 elif value == option_key:
182 182
                     return
183  
-            raise exceptions.ValidationError(
184  
-                self.error_messages['invalid_choice'] % value)
  183
+            msg = self.error_messages['invalid_choice'] % value
  184
+            raise exceptions.ValidationError(msg)
185 185
 
186 186
         if value is None and not self.null:
187 187
             raise exceptions.ValidationError(self.error_messages['null'])
@@ -638,11 +638,7 @@ def formfield(self, **kwargs):
638 638
         defaults.update(kwargs)
639 639
         return super(CommaSeparatedIntegerField, self).formfield(**defaults)
640 640
 
641  
-ansi_date_re = re.compile(r'^\d{4}-\d{1,2}-\d{1,2}$')
642  
-
643 641
 class DateField(Field):
644  
-    description = _("Date (without time)")
645  
-
646 642
     empty_strings_allowed = False
647 643
     default_error_messages = {
648 644
         'invalid': _(u"'%s' value has an invalid date format. It must be "
@@ -650,11 +646,11 @@ class DateField(Field):
650 646
         'invalid_date': _(u"'%s' value has the correct format (YYYY-MM-DD) "
651 647
                           u"but it is an invalid date."),
652 648
     }
  649
+    description = _("Date (without time)")
  650
+
653 651
     def __init__(self, verbose_name=None, name=None, auto_now=False,
654 652
                  auto_now_add=False, **kwargs):
655 653
         self.auto_now, self.auto_now_add = auto_now, auto_now_add
656  
-        # HACKs : auto_now_add/auto_now should be done as a default or a
657  
-        # pre_save.
658 654
         if auto_now or auto_now_add:
659 655
             kwargs['editable'] = False
660 656
             kwargs['blank'] = True
@@ -671,20 +667,19 @@ def to_python(self, value):
671 667
         if isinstance(value, datetime.date):
672 668
             return value
673 669
 
674  
-        if not ansi_date_re.search(value):
675  
-            msg = self.error_messages['invalid'] % str(value)
676  
-            raise exceptions.ValidationError(msg)
677  
-        # Now that we have the date string in YYYY-MM-DD format, check to make
678  
-        # sure it's a valid date.
679  
-        # We could use time.strptime here and catch errors, but datetime.date
680  
-        # produces much friendlier error messages.
681  
-        year, month, day = map(int, value.split('-'))
  670
+        value = smart_str(value)
  671
+
682 672
         try:
683  
-            return datetime.date(year, month, day)
684  
-        except ValueError, e:
685  
-            msg = self.error_messages['invalid_date'] % str(value)
  673
+            parsed = parse_date(value)
  674
+            if parsed is not None:
  675
+                return parsed
  676
+        except ValueError:
  677
+            msg = self.error_messages['invalid_date'] % value
686 678
             raise exceptions.ValidationError(msg)
687 679
 
  680
+        msg = self.error_messages['invalid'] % value
  681
+        raise exceptions.ValidationError(msg)
  682
+
688 683
     def pre_save(self, model_instance, add):
689 684
         if self.auto_now or (self.auto_now_add and add):
690 685
             value = datetime.date.today()
@@ -721,11 +716,7 @@ def get_db_prep_value(self, value, connection, prepared=False):
721 716
 
722 717
     def value_to_string(self, obj):
723 718
         val = self._get_val_from_obj(obj)
724  
-        if val is None:
725  
-            data = ''
726  
-        else:
727  
-            data = str(val)
728  
-        return data
  719
+        return '' if val is None else val.isoformat()
729 720
 
730 721
     def formfield(self, **kwargs):
731 722
         defaults = {'form_class': forms.DateField}
@@ -733,13 +724,20 @@ def formfield(self, **kwargs):
733 724
         return super(DateField, self).formfield(**defaults)
734 725
 
735 726
 class DateTimeField(DateField):
  727
+    empty_strings_allowed = False
736 728
     default_error_messages = {
737  
-        'invalid': _(u"'%s' value either has an invalid valid format (The "
738  
-                     u"format must be YYYY-MM-DD HH:MM[:ss[.uuuuuu]]) or is "
739  
-                     u"an invalid date/time."),
  729
+        'invalid': _(u"'%s' value has an invalid format. It must be in "
  730
+                     u"YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."),
  731
+        'invalid_date': _(u"'%s' value has the correct format "
  732
+                          u"(YYYY-MM-DD) but it is an invalid date."),
  733
+        'invalid_datetime': _(u"'%s' value has the correct format "
  734
+                              u"(YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]) "
  735
+                              u"but it is an invalid date/time."),
740 736
     }
741 737
     description = _("Date (with time)")
742 738
 
  739
+    # __init__ is inherited from DateField
  740
+
743 741
     def get_internal_type(self):
744 742
         return "DateTimeField"
745 743
 
@@ -751,59 +749,59 @@ def to_python(self, value):
751 749
         if isinstance(value, datetime.date):
752 750
             return datetime.datetime(value.year, value.month, value.day)
753 751
 
754  
-        # Attempt to parse a datetime:
755 752
         value = smart_str(value)
756  
-        # split usecs, because they are not recognized by strptime.
757  
-        if '.' in value:
758  
-            try:
759  
-                value, usecs = value.split('.')
760  
-                usecs = int(usecs)
761  
-            except ValueError:
762  
-                raise exceptions.ValidationError(
763  
-                    self.error_messages['invalid'] % str(value))
764  
-        else:
765  
-            usecs = 0
766  
-        kwargs = {'microsecond': usecs}
767  
-        try: # Seconds are optional, so try converting seconds first.
768  
-            return datetime.datetime(
769  
-                *time.strptime(value, '%Y-%m-%d %H:%M:%S')[:6], **kwargs)
770 753
 
  754
+        try:
  755
+            parsed = parse_datetime(value)
  756
+            if parsed is not None:
  757
+                return parsed
  758
+        except ValueError:
  759
+            msg = self.error_messages['invalid_datetime'] % value
  760
+            raise exceptions.ValidationError(msg)
  761
+
  762
+        try:
  763
+            parsed = parse_date(value)
  764
+            if parsed is not None:
  765
+                return datetime.datetime(parsed.year, parsed.month, parsed.day)
771 766
         except ValueError:
772  
-            try: # Try without seconds.
773  
-                return datetime.datetime(
774  
-                    *time.strptime(value, '%Y-%m-%d %H:%M')[:5], **kwargs)
775  
-            except ValueError: # Try without hour/minutes/seconds.
776  
-                try:
777  
-                    return datetime.datetime(
778  
-                        *time.strptime(value, '%Y-%m-%d')[:3], **kwargs)
779  
-                except ValueError:
780  
-                    raise exceptions.ValidationError(
781  
-                        self.error_messages['invalid'] % str(value))
  767
+            msg = self.error_messages['invalid_date'] % value
  768
+            raise exceptions.ValidationError(msg)
  769
+
  770
+        msg = self.error_messages['invalid'] % value
  771
+        raise exceptions.ValidationError(msg)
782 772
 
783 773
     def pre_save(self, model_instance, add):
784 774
         if self.auto_now or (self.auto_now_add and add):
785  
-            value = datetime.datetime.now()
  775
+            value = timezone.now()
786 776
             setattr(model_instance, self.attname, value)
787 777
             return value
788 778
         else:
789 779
             return super(DateTimeField, self).pre_save(model_instance, add)
790 780
 
  781
+    # contribute_to_class is inherited from DateField, it registers
  782
+    # get_next_by_FOO and get_prev_by_FOO
  783
+
  784
+    # get_prep_lookup is inherited from DateField
  785
+
791 786
     def get_prep_value(self, value):
792  
-        return self.to_python(value)
  787
+        value = self.to_python(value)
  788
+        if settings.USE_TZ and timezone.is_naive(value):
  789
+            # For backwards compatibility, interpret naive datetimes in local
  790
+            # time. This won't work during DST change, but we can't do much
  791
+            # about it, so we let the exceptions percolate up the call stack.
  792
+            default_timezone = timezone.get_default_timezone()
  793
+            value = timezone.make_aware(value, default_timezone)
  794
+        return value
793 795
 
794 796
     def get_db_prep_value(self, value, connection, prepared=False):
795  
-        # Casts dates into the format expected by the backend
  797
+        # Casts datetimes into the format expected by the backend
796 798
         if not prepared:
797 799
             value = self.get_prep_value(value)
798 800
         return connection.ops.value_to_db_datetime(value)
799 801
 
800 802
     def value_to_string(self, obj):
801 803
         val = self._get_val_from_obj(obj)
802  
-        if val is None:
803  
-            data = ''
804  
-        else:
805  
-            data = str(val.replace(microsecond=0, tzinfo=None))
806  
-        return data
  804
+        return '' if val is None else val.isoformat()
807 805
 
808 806
     def formfield(self, **kwargs):
809 807
         defaults = {'form_class': forms.DateTimeField}
@@ -1158,17 +1156,21 @@ def formfield(self, **kwargs):
1158 1156
         return super(TextField, self).formfield(**defaults)
1159 1157
 
1160 1158
 class TimeField(Field):
1161  
-    description = _("Time")
1162  
-
1163 1159
     empty_strings_allowed = False
1164 1160
     default_error_messages = {
1165  
-        'invalid': _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.'),
  1161
+        'invalid': _(u"'%s' value has an invalid format. It must be in "
  1162
+                     u"HH:MM[:ss[.uuuuuu]] format."),
  1163
+        'invalid_time': _(u"'%s' value has the correct format "
  1164
+                          u"(HH:MM[:ss[.uuuuuu]]) but it is an invalid time."),
1166 1165
     }
  1166
+    description = _("Time")
  1167
+
1167 1168
     def __init__(self, verbose_name=None, name=None, auto_now=False,
1168 1169
                  auto_now_add=False, **kwargs):
1169 1170
         self.auto_now, self.auto_now_add = auto_now, auto_now_add
1170 1171
         if auto_now or auto_now_add:
1171 1172
             kwargs['editable'] = False
  1173
+            kwargs['blank'] = True
1172 1174
         Field.__init__(self, verbose_name, name, **kwargs)
1173 1175
 
1174 1176
     def get_internal_type(self):
@@ -1185,30 +1187,18 @@ def to_python(self, value):
1185 1187
             # database backend (e.g. Oracle), so we'll be accommodating.
1186 1188
             return value.time()
1187 1189
 
1188  
-        # Attempt to parse a datetime:
1189 1190
         value = smart_str(value)
1190  
-        # split usecs, because they are not recognized by strptime.
1191  
-        if '.' in value:
1192  
-            try:
1193  
-                value, usecs = value.split('.')
1194  
-                usecs = int(usecs)
1195  
-            except ValueError:
1196  
-                raise exceptions.ValidationError(
1197  
-                    self.error_messages['invalid'])
1198  
-        else:
1199  
-            usecs = 0
1200  
-        kwargs = {'microsecond': usecs}
1201 1191
 
1202  
-        try: # Seconds are optional, so try converting seconds first.
1203  
-            return datetime.time(*time.strptime(value, '%H:%M:%S')[3:6],
1204  
-                                 **kwargs)
  1192
+        try:
  1193
+            parsed = parse_time(value)
  1194
+            if parsed is not None:
  1195
+                return parsed
1205 1196
         except ValueError:
1206  
-            try: # Try without seconds.
1207  
-                return datetime.time(*time.strptime(value, '%H:%M')[3:5],
1208  
-                                         **kwargs)
1209  
-            except ValueError:
1210  
-                raise exceptions.ValidationError(
1211  
-                    self.error_messages['invalid'])
  1197
+            msg = self.error_messages['invalid_time'] % value
  1198
+            raise exceptions.ValidationError(msg)
  1199
+
  1200
+        msg = self.error_messages['invalid'] % value
  1201
+        raise exceptions.ValidationError(msg)
1212 1202
 
1213 1203
     def pre_save(self, model_instance, add):
1214 1204
         if self.auto_now or (self.auto_now_add and add):
@@ -1229,11 +1219,7 @@ def get_db_prep_value(self, value, connection, prepared=False):
1229 1219
 
1230 1220
     def value_to_string(self, obj):
1231 1221
         val = self._get_val_from_obj(obj)
1232  
-        if val is None:
1233  
-            data = ''
1234  
-        else:
1235  
-            data = str(val.replace(microsecond=0))
1236  
-        return data
  1222
+        return '' if val is None else val.isoformat()
1237 1223
 
1238 1224
     def formfield(self, **kwargs):
1239 1225
         defaults = {'form_class': forms.TimeField}
2  django/db/utils.py
@@ -66,7 +66,7 @@ def ensure_defaults(self, alias):
66 66
         if conn['ENGINE'] == 'django.db.backends.' or not conn['ENGINE']:
67 67
             conn['ENGINE'] = 'django.db.backends.dummy'
68 68
         conn.setdefault('OPTIONS', {})
69  
-        conn.setdefault('TIME_ZONE', settings.TIME_ZONE)
  69
+        conn.setdefault('TIME_ZONE', 'UTC' if settings.USE_TZ else settings.TIME_ZONE)
70 70
         for setting in ['NAME', 'USER', 'PASSWORD', 'HOST', 'PORT']:
71 71
             conn.setdefault(setting, '')
72 72
         for setting in ['TEST_CHARSET', 'TEST_COLLATION', 'TEST_NAME', 'TEST_MIRROR']:
18  django/forms/fields.py
@@ -17,7 +17,7 @@
17 17
 
18 18
 from django.core import validators
19 19
 from django.core.exceptions import ValidationError
20  
-from django.forms.util import ErrorList
  20
+from django.forms.util import ErrorList, from_current_timezone, to_current_timezone
21 21
 from django.forms.widgets import (TextInput, PasswordInput, HiddenInput,
22 22
     MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select,
23 23
     NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput,
@@ -409,6 +409,11 @@ class DateTimeField(BaseTemporalField):
409 409
         'invalid': _(u'Enter a valid date/time.'),
410 410
     }
411 411
 
  412
+    def prepare_value(self, value):
  413
+        if isinstance(value, datetime.datetime):
  414
+            value = to_current_timezone(value)
  415
+        return value
  416
+
412 417
     def to_python(self, value):
413 418
         """
414 419
         Validates that the input can be converted to a datetime. Returns a
@@ -417,9 +422,10 @@ def to_python(self, value):
417 422
         if value in validators.EMPTY_VALUES:
418 423
             return None
419 424
         if isinstance(value, datetime.datetime):
420  
-            return value
  425
+            return from_current_timezone(value)
421 426
         if isinstance(value, datetime.date):
422  
-            return datetime.datetime(value.year, value.month, value.day)
  427
+            result = datetime.datetime(value.year, value.month, value.day)
  428
+            return from_current_timezone(result)
423 429
         if isinstance(value, list):
424 430
             # Input comes from a SplitDateTimeWidget, for example. So, it's two
425 431
             # components: date and time.
@@ -428,7 +434,8 @@ def to_python(self, value):
428 434
             if value[0] in validators.EMPTY_VALUES and value[1] in validators.EMPTY_VALUES:
429 435
                 return None
430 436
             value = '%s %s' % tuple(value)
431  
-        return super(DateTimeField, self).to_python(value)
  437
+        result = super(DateTimeField, self).to_python(value)
  438
+        return from_current_timezone(result)
432 439
 
433 440
     def strptime(self, value, format):
434 441
         return datetime.datetime.strptime(value, format)
@@ -979,7 +986,8 @@ def compress(self, data_list):
979 986
                 raise ValidationError(self.error_messages['invalid_date'])
980 987
             if data_list[1] in validators.EMPTY_VALUES:
981 988
                 raise ValidationError(self.error_messages['invalid_time'])
982  
-            return datetime.datetime.combine(*data_list)
  989
+            result = datetime.datetime.combine(*data_list)
  990
+            return from_current_timezone(result)
983 991
         return None
984 992
 
985 993
 
31  django/forms/util.py
... ...
@@ -1,6 +1,9 @@
  1
+from django.conf import settings
1 2
 from django.utils.html import conditional_escape
2 3
 from django.utils.encoding import StrAndUnicode, force_unicode
3 4
 from django.utils.safestring import mark_safe
  5
+from django.utils import timezone
  6
+from django.utils.translation import ugettext_lazy as _
4 7
 
5 8
 # Import ValidationError so that it can be imported from this
6 9
 # module to maintain backwards compatibility.
@@ -52,3 +55,31 @@ def as_text(self):
52 55
     def __repr__(self):
53 56
         return repr([force_unicode(e) for e in self])
54 57
 
  58
+# Utilities for time zone support in DateTimeField et al.
  59
+
  60
+def from_current_timezone(value):
  61
+    """
  62
+    When time zone support is enabled, convert naive datetimes
  63
+    entered in the current time zone to aware datetimes.
  64
+    """
  65
+    if settings.USE_TZ and value is not None and timezone.is_naive(value):
  66
+        current_timezone = timezone.get_current_timezone()
  67
+        try:
  68
+            return timezone.make_aware(value, current_timezone)
  69
+        except Exception, e:
  70
+            raise ValidationError(_('%(datetime)s couldn\'t be interpreted '
  71
+                                    'in time zone %(current_timezone)s; it '
  72
+                                    'may be ambiguous or it may not exist.')
  73
+                                  % {'datetime': value,
  74
+                                     'current_timezone': current_timezone})
  75
+    return value
  76
+
  77
+def to_current_timezone(value):
  78
+    """
  79
+    When time zone support is enabled, convert aware datetimes
  80
+    to naive dateimes in the current time zone for display.
  81
+    """
  82
+    if settings.USE_TZ and value is not None and timezone.is_aware(value):
  83
+        current_timezone = timezone.get_current_timezone()
  84
+        return timezone.make_naive(value, current_timezone)
  85
+    return value
3  django/forms/widgets.py
@@ -10,7 +10,7 @@
10 10
 from urlparse import urljoin
11 11
 
12 12
 from django.conf import settings
13  
-from django.forms.util import flatatt
  13
+from django.forms.util import flatatt, to_current_timezone
14 14
 from django.utils.datastructures import MultiValueDict, MergeDict
15 15
 from django.utils.html import escape, conditional_escape
16 16
 from django.utils.translation import ugettext, ugettext_lazy
@@ -847,6 +847,7 @@ def __init__(self, attrs=None, date_format=None, time_format=None):
847 847
 
848 848
     def decompress(self, value):
849 849
         if value: