App Engine Python SDK version 1.7.4 (2)
[gae.git] / python / lib / django_1_4 / tests / modeltests / timezones / tests.py
blob171c2187f22171461dac17e480cbcc0d4a8a45f7
1 from __future__ import with_statement
3 import datetime
4 import os
5 import sys
6 import time
7 import warnings
9 try:
10 import pytz
11 except ImportError:
12 pytz = None
14 from django.conf import settings
15 from django.core import serializers
16 from django.core.urlresolvers import reverse
17 from django.db import connection
18 from django.db.models import Min, Max
19 from django.http import HttpRequest
20 from django.template import Context, RequestContext, Template, TemplateSyntaxError
21 from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
22 from django.test.utils import override_settings
23 from django.utils import timezone
24 from django.utils.tzinfo import FixedOffset
25 from django.utils.unittest import skipIf, skipUnless
27 from .forms import EventForm, EventSplitForm, EventModelForm
28 from .models import Event, MaybeEvent, Session, SessionEvent, Timestamp
31 # These tests use the EAT (Eastern Africa Time) and ICT (Indochina Time)
32 # who don't have Daylight Saving Time, so we can represent them easily
33 # with FixedOffset, and use them directly as tzinfo in the constructors.
35 # settings.TIME_ZONE is forced to EAT. Most tests use a variant of
36 # datetime.datetime(2011, 9, 1, 13, 20, 30), which translates to
37 # 10:20:30 in UTC and 17:20:30 in ICT.
39 UTC = timezone.utc
40 EAT = FixedOffset(180) # Africa/Nairobi
41 ICT = FixedOffset(420) # Asia/Bangkok
43 TZ_SUPPORT = hasattr(time, 'tzset')
45 # On OSes that don't provide tzset (Windows), we can't set the timezone
46 # in which the program runs. As a consequence, we must skip tests that
47 # don't enforce a specific timezone (with timezone.override or equivalent),
48 # or attempt to interpret naive datetimes in the default timezone.
50 requires_tz_support = skipUnless(TZ_SUPPORT,
51 "This test relies on the ability to run a program in an arbitrary "
52 "time zone, but your operating system isn't able to do that.")
55 class BaseDateTimeTests(TestCase):
57 @classmethod
58 def setUpClass(self):
59 self._old_time_zone = settings.TIME_ZONE
60 settings.TIME_ZONE = connection.settings_dict['TIME_ZONE'] = 'Africa/Nairobi'
61 timezone._localtime = None
62 if TZ_SUPPORT:
63 self._old_tz = os.environ.get('TZ')
64 os.environ['TZ'] = 'Africa/Nairobi'
65 time.tzset()
67 @classmethod
68 def tearDownClass(self):
69 settings.TIME_ZONE = connection.settings_dict['TIME_ZONE'] = self._old_time_zone
70 timezone._localtime = None
71 if TZ_SUPPORT:
72 if self._old_tz is None:
73 del os.environ['TZ']
74 else:
75 os.environ['TZ'] = self._old_tz
76 time.tzset()
79 #@override_settings(USE_TZ=False)
80 class LegacyDatabaseTests(BaseDateTimeTests):
82 def test_naive_datetime(self):
83 dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
84 Event.objects.create(dt=dt)
85 event = Event.objects.get()
86 self.assertEqual(event.dt, dt)
88 @skipUnlessDBFeature('supports_microsecond_precision')
89 def test_naive_datetime_with_microsecond(self):
90 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
91 Event.objects.create(dt=dt)
92 event = Event.objects.get()
93 self.assertEqual(event.dt, dt)
95 @skipIfDBFeature('supports_microsecond_precision')
96 def test_naive_datetime_with_microsecond_unsupported(self):
97 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
98 Event.objects.create(dt=dt)
99 event = Event.objects.get()
100 # microseconds are lost during a round-trip in the database
101 self.assertEqual(event.dt, dt.replace(microsecond=0))
103 @skipUnlessDBFeature('supports_timezones')
104 def test_aware_datetime_in_local_timezone(self):
105 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
106 Event.objects.create(dt=dt)
107 event = Event.objects.get()
108 self.assertIsNone(event.dt.tzinfo)
109 # interpret the naive datetime in local time to get the correct value
110 self.assertEqual(event.dt.replace(tzinfo=EAT), dt)
112 @skipUnlessDBFeature('supports_timezones')
113 @skipUnlessDBFeature('supports_microsecond_precision')
114 def test_aware_datetime_in_local_timezone_with_microsecond(self):
115 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
116 Event.objects.create(dt=dt)
117 event = Event.objects.get()
118 self.assertIsNone(event.dt.tzinfo)
119 # interpret the naive datetime in local time to get the correct value
120 self.assertEqual(event.dt.replace(tzinfo=EAT), dt)
122 # This combination actually never happens.
123 @skipUnlessDBFeature('supports_timezones')
124 @skipIfDBFeature('supports_microsecond_precision')
125 def test_aware_datetime_in_local_timezone_with_microsecond_unsupported(self):
126 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
127 Event.objects.create(dt=dt)
128 event = Event.objects.get()
129 self.assertIsNone(event.dt.tzinfo)
130 # interpret the naive datetime in local time to get the correct value
131 # microseconds are lost during a round-trip in the database
132 self.assertEqual(event.dt.replace(tzinfo=EAT), dt.replace(microsecond=0))
134 @skipUnlessDBFeature('supports_timezones')
135 @skipIfDBFeature('needs_datetime_string_cast')
136 def test_aware_datetime_in_utc(self):
137 dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
138 Event.objects.create(dt=dt)
139 event = Event.objects.get()
140 self.assertIsNone(event.dt.tzinfo)
141 # interpret the naive datetime in local time to get the correct value
142 self.assertEqual(event.dt.replace(tzinfo=EAT), dt)
144 # This combination is no longer possible since timezone support
145 # was removed from the SQLite backend -- it didn't work.
146 @skipUnlessDBFeature('supports_timezones')
147 @skipUnlessDBFeature('needs_datetime_string_cast')
148 def test_aware_datetime_in_utc_unsupported(self):
149 dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
150 Event.objects.create(dt=dt)
151 event = Event.objects.get()
152 self.assertIsNone(event.dt.tzinfo)
153 # django.db.backend.utils.typecast_dt will just drop the
154 # timezone, so a round-trip in the database alters the data (!)
155 # interpret the naive datetime in local time and you get a wrong value
156 self.assertNotEqual(event.dt.replace(tzinfo=EAT), dt)
157 # interpret the naive datetime in original time to get the correct value
158 self.assertEqual(event.dt.replace(tzinfo=UTC), dt)
160 @skipUnlessDBFeature('supports_timezones')
161 @skipIfDBFeature('needs_datetime_string_cast')
162 def test_aware_datetime_in_other_timezone(self):
163 dt = datetime.datetime(2011, 9, 1, 17, 20, 30, tzinfo=ICT)
164 Event.objects.create(dt=dt)
165 event = Event.objects.get()
166 self.assertIsNone(event.dt.tzinfo)
167 # interpret the naive datetime in local time to get the correct value
168 self.assertEqual(event.dt.replace(tzinfo=EAT), dt)
170 # This combination is no longer possible since timezone support
171 # was removed from the SQLite backend -- it didn't work.
172 @skipUnlessDBFeature('supports_timezones')
173 @skipUnlessDBFeature('needs_datetime_string_cast')
174 def test_aware_datetime_in_other_timezone_unsupported(self):
175 dt = datetime.datetime(2011, 9, 1, 17, 20, 30, tzinfo=ICT)
176 Event.objects.create(dt=dt)
177 event = Event.objects.get()
178 self.assertIsNone(event.dt.tzinfo)
179 # django.db.backend.utils.typecast_dt will just drop the
180 # timezone, so a round-trip in the database alters the data (!)
181 # interpret the naive datetime in local time and you get a wrong value
182 self.assertNotEqual(event.dt.replace(tzinfo=EAT), dt)
183 # interpret the naive datetime in original time to get the correct value
184 self.assertEqual(event.dt.replace(tzinfo=ICT), dt)
186 @skipIfDBFeature('supports_timezones')
187 def test_aware_datetime_unspported(self):
188 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
189 with self.assertRaises(ValueError):
190 Event.objects.create(dt=dt)
192 def test_auto_now_and_auto_now_add(self):
193 now = datetime.datetime.now()
194 past = now - datetime.timedelta(seconds=2)
195 future = now + datetime.timedelta(seconds=2)
196 Timestamp.objects.create()
197 ts = Timestamp.objects.get()
198 self.assertLess(past, ts.created)
199 self.assertLess(past, ts.updated)
200 self.assertGreater(future, ts.updated)
201 self.assertGreater(future, ts.updated)
203 def test_query_filter(self):
204 dt1 = datetime.datetime(2011, 9, 1, 12, 20, 30)
205 dt2 = datetime.datetime(2011, 9, 1, 14, 20, 30)
206 Event.objects.create(dt=dt1)
207 Event.objects.create(dt=dt2)
208 self.assertEqual(Event.objects.filter(dt__gte=dt1).count(), 2)
209 self.assertEqual(Event.objects.filter(dt__gt=dt1).count(), 1)
210 self.assertEqual(Event.objects.filter(dt__gte=dt2).count(), 1)
211 self.assertEqual(Event.objects.filter(dt__gt=dt2).count(), 0)
213 def test_query_date_related_filters(self):
214 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0))
215 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0))
216 self.assertEqual(Event.objects.filter(dt__year=2011).count(), 2)
217 self.assertEqual(Event.objects.filter(dt__month=1).count(), 2)
218 self.assertEqual(Event.objects.filter(dt__day=1).count(), 2)
219 self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 2)
221 def test_query_aggregation(self):
222 # Only min and max make sense for datetimes.
223 Event.objects.create(dt=datetime.datetime(2011, 9, 1, 23, 20, 20))
224 Event.objects.create(dt=datetime.datetime(2011, 9, 1, 13, 20, 30))
225 Event.objects.create(dt=datetime.datetime(2011, 9, 1, 3, 20, 40))
226 result = Event.objects.all().aggregate(Min('dt'), Max('dt'))
227 self.assertEqual(result, {
228 'dt__min': datetime.datetime(2011, 9, 1, 3, 20, 40),
229 'dt__max': datetime.datetime(2011, 9, 1, 23, 20, 20),
232 def test_query_annotation(self):
233 # Only min and max make sense for datetimes.
234 morning = Session.objects.create(name='morning')
235 afternoon = Session.objects.create(name='afternoon')
236 SessionEvent.objects.create(dt=datetime.datetime(2011, 9, 1, 23, 20, 20), session=afternoon)
237 SessionEvent.objects.create(dt=datetime.datetime(2011, 9, 1, 13, 20, 30), session=afternoon)
238 SessionEvent.objects.create(dt=datetime.datetime(2011, 9, 1, 3, 20, 40), session=morning)
239 morning_min_dt = datetime.datetime(2011, 9, 1, 3, 20, 40)
240 afternoon_min_dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
241 self.assertQuerysetEqual(
242 Session.objects.annotate(dt=Min('events__dt')).order_by('dt'),
243 [morning_min_dt, afternoon_min_dt],
244 transform=lambda d: d.dt)
245 self.assertQuerysetEqual(
246 Session.objects.annotate(dt=Min('events__dt')).filter(dt__lt=afternoon_min_dt),
247 [morning_min_dt],
248 transform=lambda d: d.dt)
249 self.assertQuerysetEqual(
250 Session.objects.annotate(dt=Min('events__dt')).filter(dt__gte=afternoon_min_dt),
251 [afternoon_min_dt],
252 transform=lambda d: d.dt)
254 def test_query_dates(self):
255 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0))
256 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0))
257 self.assertQuerysetEqual(Event.objects.dates('dt', 'year'),
258 [datetime.datetime(2011, 1, 1)], transform=lambda d: d)
259 self.assertQuerysetEqual(Event.objects.dates('dt', 'month'),
260 [datetime.datetime(2011, 1, 1)], transform=lambda d: d)
261 self.assertQuerysetEqual(Event.objects.dates('dt', 'day'),
262 [datetime.datetime(2011, 1, 1)], transform=lambda d: d)
264 def test_raw_sql(self):
265 # Regression test for #17755
266 dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
267 event = Event.objects.create(dt=dt)
268 self.assertQuerysetEqual(
269 Event.objects.raw('SELECT * FROM timezones_event WHERE dt = %s', [dt]),
270 [event],
271 transform=lambda d: d)
273 LegacyDatabaseTests = override_settings(USE_TZ=False)(LegacyDatabaseTests)
276 #@override_settings(USE_TZ=True)
277 class NewDatabaseTests(BaseDateTimeTests):
279 @requires_tz_support
280 @skipIf(sys.version_info < (2, 6), "this test requires Python >= 2.6")
281 def test_naive_datetime(self):
282 dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
283 with warnings.catch_warnings(record=True) as recorded:
284 warnings.simplefilter('always')
285 Event.objects.create(dt=dt)
286 self.assertEqual(len(recorded), 1)
287 msg = str(recorded[0].message)
288 self.assertTrue(msg.startswith("DateTimeField received a naive datetime"))
289 event = Event.objects.get()
290 # naive datetimes are interpreted in local time
291 self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
293 @requires_tz_support
294 @skipIf(sys.version_info < (2, 6), "this test requires Python >= 2.6")
295 def test_datetime_from_date(self):
296 dt = datetime.date(2011, 9, 1)
297 with warnings.catch_warnings(record=True) as recorded:
298 warnings.simplefilter('always')
299 Event.objects.create(dt=dt)
300 self.assertEqual(len(recorded), 1)
301 msg = str(recorded[0].message)
302 self.assertTrue(msg.startswith("DateTimeField received a naive datetime"))
303 event = Event.objects.get()
304 self.assertEqual(event.dt, datetime.datetime(2011, 9, 1, tzinfo=EAT))
306 @requires_tz_support
307 @skipIf(sys.version_info < (2, 6), "this test requires Python >= 2.6")
308 @skipUnlessDBFeature('supports_microsecond_precision')
309 def test_naive_datetime_with_microsecond(self):
310 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
311 with warnings.catch_warnings(record=True) as recorded:
312 warnings.simplefilter('always')
313 Event.objects.create(dt=dt)
314 self.assertEqual(len(recorded), 1)
315 msg = str(recorded[0].message)
316 self.assertTrue(msg.startswith("DateTimeField received a naive datetime"))
317 event = Event.objects.get()
318 # naive datetimes are interpreted in local time
319 self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
321 @requires_tz_support
322 @skipIf(sys.version_info < (2, 6), "this test requires Python >= 2.6")
323 @skipIfDBFeature('supports_microsecond_precision')
324 def test_naive_datetime_with_microsecond_unsupported(self):
325 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
326 with warnings.catch_warnings(record=True) as recorded:
327 warnings.simplefilter('always')
328 Event.objects.create(dt=dt)
329 self.assertEqual(len(recorded), 1)
330 msg = str(recorded[0].message)
331 self.assertTrue(msg.startswith("DateTimeField received a naive datetime"))
332 event = Event.objects.get()
333 # microseconds are lost during a round-trip in the database
334 # naive datetimes are interpreted in local time
335 self.assertEqual(event.dt, dt.replace(microsecond=0, tzinfo=EAT))
337 def test_aware_datetime_in_local_timezone(self):
338 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
339 Event.objects.create(dt=dt)
340 event = Event.objects.get()
341 self.assertEqual(event.dt, dt)
343 @skipUnlessDBFeature('supports_microsecond_precision')
344 def test_aware_datetime_in_local_timezone_with_microsecond(self):
345 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
346 Event.objects.create(dt=dt)
347 event = Event.objects.get()
348 self.assertEqual(event.dt, dt)
350 @skipIfDBFeature('supports_microsecond_precision')
351 def test_aware_datetime_in_local_timezone_with_microsecond_unsupported(self):
352 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
353 Event.objects.create(dt=dt)
354 event = Event.objects.get()
355 # microseconds are lost during a round-trip in the database
356 self.assertEqual(event.dt, dt.replace(microsecond=0))
358 def test_aware_datetime_in_utc(self):
359 dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
360 Event.objects.create(dt=dt)
361 event = Event.objects.get()
362 self.assertEqual(event.dt, dt)
364 def test_aware_datetime_in_other_timezone(self):
365 dt = datetime.datetime(2011, 9, 1, 17, 20, 30, tzinfo=ICT)
366 Event.objects.create(dt=dt)
367 event = Event.objects.get()
368 self.assertEqual(event.dt, dt)
370 def test_auto_now_and_auto_now_add(self):
371 now = timezone.now()
372 past = now - datetime.timedelta(seconds=2)
373 future = now + datetime.timedelta(seconds=2)
374 Timestamp.objects.create()
375 ts = Timestamp.objects.get()
376 self.assertLess(past, ts.created)
377 self.assertLess(past, ts.updated)
378 self.assertGreater(future, ts.updated)
379 self.assertGreater(future, ts.updated)
381 def test_query_filter(self):
382 dt1 = datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=EAT)
383 dt2 = datetime.datetime(2011, 9, 1, 14, 20, 30, tzinfo=EAT)
384 Event.objects.create(dt=dt1)
385 Event.objects.create(dt=dt2)
386 self.assertEqual(Event.objects.filter(dt__gte=dt1).count(), 2)
387 self.assertEqual(Event.objects.filter(dt__gt=dt1).count(), 1)
388 self.assertEqual(Event.objects.filter(dt__gte=dt2).count(), 1)
389 self.assertEqual(Event.objects.filter(dt__gt=dt2).count(), 0)
391 @skipIf(pytz is None, "this test requires pytz")
392 def test_query_filter_with_pytz_timezones(self):
393 tz = pytz.timezone('Europe/Paris')
394 dt = datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=tz)
395 Event.objects.create(dt=dt)
396 next = dt + datetime.timedelta(seconds=3)
397 prev = dt - datetime.timedelta(seconds=3)
398 self.assertEqual(Event.objects.filter(dt__exact=dt).count(), 1)
399 self.assertEqual(Event.objects.filter(dt__exact=next).count(), 0)
400 self.assertEqual(Event.objects.filter(dt__in=(prev, next)).count(), 0)
401 self.assertEqual(Event.objects.filter(dt__in=(prev, dt, next)).count(), 1)
402 self.assertEqual(Event.objects.filter(dt__range=(prev, next)).count(), 1)
404 @requires_tz_support
405 @skipIf(sys.version_info < (2, 6), "this test requires Python >= 2.6")
406 def test_query_filter_with_naive_datetime(self):
407 dt = datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=EAT)
408 Event.objects.create(dt=dt)
409 dt = dt.replace(tzinfo=None)
410 with warnings.catch_warnings(record=True) as recorded:
411 warnings.simplefilter('always')
412 # naive datetimes are interpreted in local time
413 self.assertEqual(Event.objects.filter(dt__exact=dt).count(), 1)
414 self.assertEqual(Event.objects.filter(dt__lte=dt).count(), 1)
415 self.assertEqual(Event.objects.filter(dt__gt=dt).count(), 0)
416 self.assertEqual(len(recorded), 3)
417 for warning in recorded:
418 msg = str(warning.message)
419 self.assertTrue(msg.startswith("DateTimeField received a naive datetime"))
421 def test_query_date_related_filters(self):
422 # These two dates fall in the same day in EAT, but in different days,
423 # years and months in UTC, and aggregation is performed in UTC when
424 # time zone support is enabled. This test could be changed if the
425 # implementation is changed to perform the aggregation is local time.
426 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=EAT))
427 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0, tzinfo=EAT))
428 self.assertEqual(Event.objects.filter(dt__year=2011).count(), 1)
429 self.assertEqual(Event.objects.filter(dt__month=1).count(), 1)
430 self.assertEqual(Event.objects.filter(dt__day=1).count(), 1)
431 self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 1)
433 def test_query_aggregation(self):
434 # Only min and max make sense for datetimes.
435 Event.objects.create(dt=datetime.datetime(2011, 9, 1, 23, 20, 20, tzinfo=EAT))
436 Event.objects.create(dt=datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT))
437 Event.objects.create(dt=datetime.datetime(2011, 9, 1, 3, 20, 40, tzinfo=EAT))
438 result = Event.objects.all().aggregate(Min('dt'), Max('dt'))
439 self.assertEqual(result, {
440 'dt__min': datetime.datetime(2011, 9, 1, 3, 20, 40, tzinfo=EAT),
441 'dt__max': datetime.datetime(2011, 9, 1, 23, 20, 20, tzinfo=EAT),
444 def test_query_annotation(self):
445 # Only min and max make sense for datetimes.
446 morning = Session.objects.create(name='morning')
447 afternoon = Session.objects.create(name='afternoon')
448 SessionEvent.objects.create(dt=datetime.datetime(2011, 9, 1, 23, 20, 20, tzinfo=EAT), session=afternoon)
449 SessionEvent.objects.create(dt=datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT), session=afternoon)
450 SessionEvent.objects.create(dt=datetime.datetime(2011, 9, 1, 3, 20, 40, tzinfo=EAT), session=morning)
451 morning_min_dt = datetime.datetime(2011, 9, 1, 3, 20, 40, tzinfo=EAT)
452 afternoon_min_dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
453 self.assertQuerysetEqual(
454 Session.objects.annotate(dt=Min('events__dt')).order_by('dt'),
455 [morning_min_dt, afternoon_min_dt],
456 transform=lambda d: d.dt)
457 self.assertQuerysetEqual(
458 Session.objects.annotate(dt=Min('events__dt')).filter(dt__lt=afternoon_min_dt),
459 [morning_min_dt],
460 transform=lambda d: d.dt)
461 self.assertQuerysetEqual(
462 Session.objects.annotate(dt=Min('events__dt')).filter(dt__gte=afternoon_min_dt),
463 [afternoon_min_dt],
464 transform=lambda d: d.dt)
466 def test_query_dates(self):
467 # Same comment as in test_query_date_related_filters.
468 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=EAT))
469 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0, tzinfo=EAT))
470 self.assertQuerysetEqual(Event.objects.dates('dt', 'year'),
471 [datetime.datetime(2010, 1, 1, tzinfo=UTC),
472 datetime.datetime(2011, 1, 1, tzinfo=UTC)],
473 transform=lambda d: d)
474 self.assertQuerysetEqual(Event.objects.dates('dt', 'month'),
475 [datetime.datetime(2010, 12, 1, tzinfo=UTC),
476 datetime.datetime(2011, 1, 1, tzinfo=UTC)],
477 transform=lambda d: d)
478 self.assertQuerysetEqual(Event.objects.dates('dt', 'day'),
479 [datetime.datetime(2010, 12, 31, tzinfo=UTC),
480 datetime.datetime(2011, 1, 1, tzinfo=UTC)],
481 transform=lambda d: d)
483 def test_raw_sql(self):
484 # Regression test for #17755
485 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
486 event = Event.objects.create(dt=dt)
487 self.assertQuerysetEqual(
488 Event.objects.raw('SELECT * FROM timezones_event WHERE dt = %s', [dt]),
489 [event],
490 transform=lambda d: d)
492 def test_null_datetime(self):
493 # Regression for #17294
494 e = MaybeEvent.objects.create()
495 self.assertEqual(e.dt, None)
497 NewDatabaseTests = override_settings(USE_TZ=True)(NewDatabaseTests)
500 class SerializationTests(BaseDateTimeTests):
502 # Backend-specific notes:
503 # - JSON supports only milliseconds, microseconds will be truncated.
504 # - PyYAML dumps the UTC offset correctly for timezone-aware datetimes,
505 # but when it loads this representation, it substracts the offset and
506 # returns a naive datetime object in UTC (http://pyyaml.org/ticket/202).
507 # Tests are adapted to take these quirks into account.
509 def test_naive_datetime(self):
510 dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
512 data = serializers.serialize('python', [Event(dt=dt)])
513 self.assertEqual(data[0]['fields']['dt'], dt)
514 obj = serializers.deserialize('python', data).next().object
515 self.assertEqual(obj.dt, dt)
517 data = serializers.serialize('json', [Event(dt=dt)])
518 self.assertIn('"fields": {"dt": "2011-09-01T13:20:30"}', data)
519 obj = serializers.deserialize('json', data).next().object
520 self.assertEqual(obj.dt, dt)
522 data = serializers.serialize('xml', [Event(dt=dt)])
523 self.assertIn('<field type="DateTimeField" name="dt">2011-09-01T13:20:30</field>', data)
524 obj = serializers.deserialize('xml', data).next().object
525 self.assertEqual(obj.dt, dt)
527 if 'yaml' in serializers.get_serializer_formats():
528 data = serializers.serialize('yaml', [Event(dt=dt)])
529 self.assertIn("- fields: {dt: !!timestamp '2011-09-01 13:20:30'}", data)
530 obj = serializers.deserialize('yaml', data).next().object
531 self.assertEqual(obj.dt, dt)
533 def test_naive_datetime_with_microsecond(self):
534 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
536 data = serializers.serialize('python', [Event(dt=dt)])
537 self.assertEqual(data[0]['fields']['dt'], dt)
538 obj = serializers.deserialize('python', data).next().object
539 self.assertEqual(obj.dt, dt)
541 data = serializers.serialize('json', [Event(dt=dt)])
542 self.assertIn('"fields": {"dt": "2011-09-01T13:20:30.405"}', data)
543 obj = serializers.deserialize('json', data).next().object
544 self.assertEqual(obj.dt, dt.replace(microsecond=405000))
546 data = serializers.serialize('xml', [Event(dt=dt)])
547 self.assertIn('<field type="DateTimeField" name="dt">2011-09-01T13:20:30.405060</field>', data)
548 obj = serializers.deserialize('xml', data).next().object
549 self.assertEqual(obj.dt, dt)
551 if 'yaml' in serializers.get_serializer_formats():
552 data = serializers.serialize('yaml', [Event(dt=dt)])
553 self.assertIn("- fields: {dt: !!timestamp '2011-09-01 13:20:30.405060'}", data)
554 obj = serializers.deserialize('yaml', data).next().object
555 self.assertEqual(obj.dt, dt)
557 def test_aware_datetime_with_microsecond(self):
558 dt = datetime.datetime(2011, 9, 1, 17, 20, 30, 405060, tzinfo=ICT)
560 data = serializers.serialize('python', [Event(dt=dt)])
561 self.assertEqual(data[0]['fields']['dt'], dt)
562 obj = serializers.deserialize('python', data).next().object
563 self.assertEqual(obj.dt, dt)
565 data = serializers.serialize('json', [Event(dt=dt)])
566 self.assertIn('"fields": {"dt": "2011-09-01T17:20:30.405+07:00"}', data)
567 obj = serializers.deserialize('json', data).next().object
568 self.assertEqual(obj.dt, dt.replace(microsecond=405000))
570 data = serializers.serialize('xml', [Event(dt=dt)])
571 self.assertIn('<field type="DateTimeField" name="dt">2011-09-01T17:20:30.405060+07:00</field>', data)
572 obj = serializers.deserialize('xml', data).next().object
573 self.assertEqual(obj.dt, dt)
575 if 'yaml' in serializers.get_serializer_formats():
576 data = serializers.serialize('yaml', [Event(dt=dt)])
577 self.assertIn("- fields: {dt: !!timestamp '2011-09-01 17:20:30.405060+07:00'}", data)
578 obj = serializers.deserialize('yaml', data).next().object
579 self.assertEqual(obj.dt.replace(tzinfo=UTC), dt)
581 def test_aware_datetime_in_utc(self):
582 dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
584 data = serializers.serialize('python', [Event(dt=dt)])
585 self.assertEqual(data[0]['fields']['dt'], dt)
586 obj = serializers.deserialize('python', data).next().object
587 self.assertEqual(obj.dt, dt)
589 data = serializers.serialize('json', [Event(dt=dt)])
590 self.assertIn('"fields": {"dt": "2011-09-01T10:20:30Z"}', data)
591 obj = serializers.deserialize('json', data).next().object
592 self.assertEqual(obj.dt, dt)
594 data = serializers.serialize('xml', [Event(dt=dt)])
595 self.assertIn('<field type="DateTimeField" name="dt">2011-09-01T10:20:30+00:00</field>', data)
596 obj = serializers.deserialize('xml', data).next().object
597 self.assertEqual(obj.dt, dt)
599 if 'yaml' in serializers.get_serializer_formats():
600 data = serializers.serialize('yaml', [Event(dt=dt)])
601 self.assertIn("- fields: {dt: !!timestamp '2011-09-01 10:20:30+00:00'}", data)
602 obj = serializers.deserialize('yaml', data).next().object
603 self.assertEqual(obj.dt.replace(tzinfo=UTC), dt)
605 def test_aware_datetime_in_local_timezone(self):
606 dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
608 data = serializers.serialize('python', [Event(dt=dt)])
609 self.assertEqual(data[0]['fields']['dt'], dt)
610 obj = serializers.deserialize('python', data).next().object
611 self.assertEqual(obj.dt, dt)
613 data = serializers.serialize('json', [Event(dt=dt)])
614 self.assertIn('"fields": {"dt": "2011-09-01T13:20:30+03:00"}', data)
615 obj = serializers.deserialize('json', data).next().object
616 self.assertEqual(obj.dt, dt)
618 data = serializers.serialize('xml', [Event(dt=dt)])
619 self.assertIn('<field type="DateTimeField" name="dt">2011-09-01T13:20:30+03:00</field>', data)
620 obj = serializers.deserialize('xml', data).next().object
621 self.assertEqual(obj.dt, dt)
623 if 'yaml' in serializers.get_serializer_formats():
624 data = serializers.serialize('yaml', [Event(dt=dt)])
625 self.assertIn("- fields: {dt: !!timestamp '2011-09-01 13:20:30+03:00'}", data)
626 obj = serializers.deserialize('yaml', data).next().object
627 self.assertEqual(obj.dt.replace(tzinfo=UTC), dt)
629 def test_aware_datetime_in_other_timezone(self):
630 dt = datetime.datetime(2011, 9, 1, 17, 20, 30, tzinfo=ICT)
632 data = serializers.serialize('python', [Event(dt=dt)])
633 self.assertEqual(data[0]['fields']['dt'], dt)
634 obj = serializers.deserialize('python', data).next().object
635 self.assertEqual(obj.dt, dt)
637 data = serializers.serialize('json', [Event(dt=dt)])
638 self.assertIn('"fields": {"dt": "2011-09-01T17:20:30+07:00"}', data)
639 obj = serializers.deserialize('json', data).next().object
640 self.assertEqual(obj.dt, dt)
642 data = serializers.serialize('xml', [Event(dt=dt)])
643 self.assertIn('<field type="DateTimeField" name="dt">2011-09-01T17:20:30+07:00</field>', data)
644 obj = serializers.deserialize('xml', data).next().object
645 self.assertEqual(obj.dt, dt)
647 if 'yaml' in serializers.get_serializer_formats():
648 data = serializers.serialize('yaml', [Event(dt=dt)])
649 self.assertIn("- fields: {dt: !!timestamp '2011-09-01 17:20:30+07:00'}", data)
650 obj = serializers.deserialize('yaml', data).next().object
651 self.assertEqual(obj.dt.replace(tzinfo=UTC), dt)
653 #@override_settings(DATETIME_FORMAT='c', USE_L10N=False, USE_TZ=True)
654 class TemplateTests(BaseDateTimeTests):
656 @requires_tz_support
657 def test_localtime_templatetag_and_filters(self):
659 Test the {% localtime %} templatetag and related filters.
661 datetimes = {
662 'utc': datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC),
663 'eat': datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT),
664 'ict': datetime.datetime(2011, 9, 1, 17, 20, 30, tzinfo=ICT),
665 'naive': datetime.datetime(2011, 9, 1, 13, 20, 30),
667 templates = {
668 'notag': Template("{% load tz %}{{ dt }}|{{ dt|localtime }}|{{ dt|utc }}|{{ dt|timezone:ICT }}"),
669 'noarg': Template("{% load tz %}{% localtime %}{{ dt }}|{{ dt|localtime }}|{{ dt|utc }}|{{ dt|timezone:ICT }}{% endlocaltime %}"),
670 'on': Template("{% load tz %}{% localtime on %}{{ dt }}|{{ dt|localtime }}|{{ dt|utc }}|{{ dt|timezone:ICT }}{% endlocaltime %}"),
671 'off': Template("{% load tz %}{% localtime off %}{{ dt }}|{{ dt|localtime }}|{{ dt|utc }}|{{ dt|timezone:ICT }}{% endlocaltime %}"),
674 # Transform a list of keys in 'datetimes' to the expected template
675 # output. This makes the definition of 'results' more readable.
676 def t(*result):
677 return '|'.join(datetimes[key].isoformat() for key in result)
679 # Results for USE_TZ = True
681 results = {
682 'utc': {
683 'notag': t('eat', 'eat', 'utc', 'ict'),
684 'noarg': t('eat', 'eat', 'utc', 'ict'),
685 'on': t('eat', 'eat', 'utc', 'ict'),
686 'off': t('utc', 'eat', 'utc', 'ict'),
688 'eat': {
689 'notag': t('eat', 'eat', 'utc', 'ict'),
690 'noarg': t('eat', 'eat', 'utc', 'ict'),
691 'on': t('eat', 'eat', 'utc', 'ict'),
692 'off': t('eat', 'eat', 'utc', 'ict'),
694 'ict': {
695 'notag': t('eat', 'eat', 'utc', 'ict'),
696 'noarg': t('eat', 'eat', 'utc', 'ict'),
697 'on': t('eat', 'eat', 'utc', 'ict'),
698 'off': t('ict', 'eat', 'utc', 'ict'),
700 'naive': {
701 'notag': t('naive', 'eat', 'utc', 'ict'),
702 'noarg': t('naive', 'eat', 'utc', 'ict'),
703 'on': t('naive', 'eat', 'utc', 'ict'),
704 'off': t('naive', 'eat', 'utc', 'ict'),
708 for k1, dt in datetimes.iteritems():
709 for k2, tpl in templates.iteritems():
710 ctx = Context({'dt': dt, 'ICT': ICT})
711 actual = tpl.render(ctx)
712 expected = results[k1][k2]
713 self.assertEqual(actual, expected, '%s / %s: %r != %r' % (k1, k2, actual, expected))
715 # Changes for USE_TZ = False
717 results['utc']['notag'] = t('utc', 'eat', 'utc', 'ict')
718 results['ict']['notag'] = t('ict', 'eat', 'utc', 'ict')
720 with self.settings(USE_TZ=False):
721 for k1, dt in datetimes.iteritems():
722 for k2, tpl in templates.iteritems():
723 ctx = Context({'dt': dt, 'ICT': ICT})
724 actual = tpl.render(ctx)
725 expected = results[k1][k2]
726 self.assertEqual(actual, expected, '%s / %s: %r != %r' % (k1, k2, actual, expected))
728 @skipIf(pytz is None, "this test requires pytz")
729 def test_localtime_filters_with_pytz(self):
731 Test the |localtime, |utc, and |timezone filters with pytz.
733 # Use a pytz timezone as local time
734 tpl = Template("{% load tz %}{{ dt|localtime }}|{{ dt|utc }}")
735 ctx = Context({'dt': datetime.datetime(2011, 9, 1, 12, 20, 30)})
737 timezone._localtime = None
738 with self.settings(TIME_ZONE='Europe/Paris'):
739 self.assertEqual(tpl.render(ctx), "2011-09-01T12:20:30+02:00|2011-09-01T10:20:30+00:00")
740 timezone._localtime = None
742 # Use a pytz timezone as argument
743 tpl = Template("{% load tz %}{{ dt|timezone:tz }}")
744 ctx = Context({'dt': datetime.datetime(2011, 9, 1, 13, 20, 30),
745 'tz': pytz.timezone('Europe/Paris')})
746 self.assertEqual(tpl.render(ctx), "2011-09-01T12:20:30+02:00")
748 # Use a pytz timezone name as argument
749 tpl = Template("{% load tz %}{{ dt|timezone:'Europe/Paris' }}")
750 ctx = Context({'dt': datetime.datetime(2011, 9, 1, 13, 20, 30),
751 'tz': pytz.timezone('Europe/Paris')})
752 self.assertEqual(tpl.render(ctx), "2011-09-01T12:20:30+02:00")
754 def test_localtime_templatetag_invalid_argument(self):
755 with self.assertRaises(TemplateSyntaxError):
756 Template("{% load tz %}{% localtime foo %}{% endlocaltime %}").render()
758 def test_localtime_filters_do_not_raise_exceptions(self):
760 Test the |localtime, |utc, and |timezone filters on bad inputs.
762 tpl = Template("{% load tz %}{{ dt }}|{{ dt|localtime }}|{{ dt|utc }}|{{ dt|timezone:tz }}")
763 with self.settings(USE_TZ=True):
764 # bad datetime value
765 ctx = Context({'dt': None, 'tz': ICT})
766 self.assertEqual(tpl.render(ctx), "None|||")
767 ctx = Context({'dt': 'not a date', 'tz': ICT})
768 self.assertEqual(tpl.render(ctx), "not a date|||")
769 # bad timezone value
770 tpl = Template("{% load tz %}{{ dt|timezone:tz }}")
771 ctx = Context({'dt': datetime.datetime(2011, 9, 1, 13, 20, 30), 'tz': None})
772 self.assertEqual(tpl.render(ctx), "")
773 ctx = Context({'dt': datetime.datetime(2011, 9, 1, 13, 20, 30), 'tz': 'not a tz'})
774 self.assertEqual(tpl.render(ctx), "")
776 @requires_tz_support
777 def test_timezone_templatetag(self):
779 Test the {% timezone %} templatetag.
781 tpl = Template("{% load tz %}"
782 "{{ dt }}|"
783 "{% timezone tz1 %}"
784 "{{ dt }}|"
785 "{% timezone tz2 %}"
786 "{{ dt }}"
787 "{% endtimezone %}"
788 "{% endtimezone %}")
789 ctx = Context({'dt': datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC),
790 'tz1': ICT, 'tz2': None})
791 self.assertEqual(tpl.render(ctx), "2011-09-01T13:20:30+03:00|2011-09-01T17:20:30+07:00|2011-09-01T13:20:30+03:00")
793 @skipIf(pytz is None, "this test requires pytz")
794 def test_timezone_templatetag_with_pytz(self):
796 Test the {% timezone %} templatetag with pytz.
798 tpl = Template("{% load tz %}{% timezone tz %}{{ dt }}{% endtimezone %}")
800 # Use a pytz timezone as argument
801 ctx = Context({'dt': datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT),
802 'tz': pytz.timezone('Europe/Paris')})
803 self.assertEqual(tpl.render(ctx), "2011-09-01T12:20:30+02:00")
805 # Use a pytz timezone name as argument
806 ctx = Context({'dt': datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT),
807 'tz': 'Europe/Paris'})
808 self.assertEqual(tpl.render(ctx), "2011-09-01T12:20:30+02:00")
810 def test_timezone_templatetag_invalid_argument(self):
811 with self.assertRaises(TemplateSyntaxError):
812 Template("{% load tz %}{% timezone %}{% endtimezone %}").render()
813 with self.assertRaises(ValueError if pytz is None else pytz.UnknownTimeZoneError):
814 Template("{% load tz %}{% timezone tz %}{% endtimezone %}").render(Context({'tz': 'foobar'}))
816 @skipIf(sys.platform.startswith('win'), "Windows uses non-standard time zone names")
817 def test_get_current_timezone_templatetag(self):
819 Test the {% get_current_timezone %} templatetag.
821 tpl = Template("{% load tz %}{% get_current_timezone as time_zone %}{{ time_zone }}")
823 self.assertEqual(tpl.render(Context()), "Africa/Nairobi" if pytz else "EAT")
824 with timezone.override(UTC):
825 self.assertEqual(tpl.render(Context()), "UTC")
827 tpl = Template("{% load tz %}{% timezone tz %}{% get_current_timezone as time_zone %}{% endtimezone %}{{ time_zone }}")
829 self.assertEqual(tpl.render(Context({'tz': ICT})), "+0700")
830 with timezone.override(UTC):
831 self.assertEqual(tpl.render(Context({'tz': ICT})), "+0700")
833 @skipIf(pytz is None, "this test requires pytz")
834 def test_get_current_timezone_templatetag_with_pytz(self):
836 Test the {% get_current_timezone %} templatetag with pytz.
838 tpl = Template("{% load tz %}{% get_current_timezone as time_zone %}{{ time_zone }}")
839 with timezone.override(pytz.timezone('Europe/Paris')):
840 self.assertEqual(tpl.render(Context()), "Europe/Paris")
842 tpl = Template("{% load tz %}{% timezone 'Europe/Paris' %}{% get_current_timezone as time_zone %}{% endtimezone %}{{ time_zone }}")
843 self.assertEqual(tpl.render(Context()), "Europe/Paris")
845 def test_get_current_timezone_templatetag_invalid_argument(self):
846 with self.assertRaises(TemplateSyntaxError):
847 Template("{% load tz %}{% get_current_timezone %}").render()
849 @skipIf(sys.platform.startswith('win'), "Windows uses non-standard time zone names")
850 def test_tz_template_context_processor(self):
852 Test the django.core.context_processors.tz template context processor.
854 tpl = Template("{{ TIME_ZONE }}")
855 self.assertEqual(tpl.render(Context()), "")
856 self.assertEqual(tpl.render(RequestContext(HttpRequest())), "Africa/Nairobi" if pytz else "EAT")
858 @requires_tz_support
859 def test_date_and_time_template_filters(self):
860 tpl = Template("{{ dt|date:'Y-m-d' }} at {{ dt|time:'H:i:s' }}")
861 ctx = Context({'dt': datetime.datetime(2011, 9, 1, 20, 20, 20, tzinfo=UTC)})
862 self.assertEqual(tpl.render(ctx), "2011-09-01 at 23:20:20")
863 with timezone.override(ICT):
864 self.assertEqual(tpl.render(ctx), "2011-09-02 at 03:20:20")
866 def test_date_and_time_template_filters_honor_localtime(self):
867 tpl = Template("{% load tz %}{% localtime off %}{{ dt|date:'Y-m-d' }} at {{ dt|time:'H:i:s' }}{% endlocaltime %}")
868 ctx = Context({'dt': datetime.datetime(2011, 9, 1, 20, 20, 20, tzinfo=UTC)})
869 self.assertEqual(tpl.render(ctx), "2011-09-01 at 20:20:20")
870 with timezone.override(ICT):
871 self.assertEqual(tpl.render(ctx), "2011-09-01 at 20:20:20")
873 def test_localtime_with_time_zone_setting_set_to_none(self):
874 # Regression for #17274
875 tpl = Template("{% load tz %}{{ dt }}")
876 ctx = Context({'dt': datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=EAT)})
878 timezone._localtime = None
879 with self.settings(TIME_ZONE=None):
880 # the actual value depends on the system time zone of the host
881 self.assertTrue(tpl.render(ctx).startswith("2011"))
882 timezone._localtime = None
884 @requires_tz_support
885 def test_now_template_tag_uses_current_time_zone(self):
886 # Regression for #17343
887 tpl = Template("{% now \"O\" %}")
888 self.assertEqual(tpl.render(Context({})), "+0300")
889 with timezone.override(ICT):
890 self.assertEqual(tpl.render(Context({})), "+0700")
892 TemplateTests = override_settings(DATETIME_FORMAT='c', USE_L10N=False, USE_TZ=True)(TemplateTests)
894 #@override_settings(DATETIME_FORMAT='c', USE_L10N=False, USE_TZ=False)
895 class LegacyFormsTests(BaseDateTimeTests):
897 def test_form(self):
898 form = EventForm({'dt': u'2011-09-01 13:20:30'})
899 self.assertTrue(form.is_valid())
900 self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 9, 1, 13, 20, 30))
902 @skipIf(pytz is None, "this test requires pytz")
903 def test_form_with_non_existent_time(self):
904 form = EventForm({'dt': u'2011-03-27 02:30:00'})
905 with timezone.override(pytz.timezone('Europe/Paris')):
906 # this is obviously a bug
907 self.assertTrue(form.is_valid())
908 self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 3, 27, 2, 30, 0))
910 @skipIf(pytz is None, "this test requires pytz")
911 def test_form_with_ambiguous_time(self):
912 form = EventForm({'dt': u'2011-10-30 02:30:00'})
913 with timezone.override(pytz.timezone('Europe/Paris')):
914 # this is obviously a bug
915 self.assertTrue(form.is_valid())
916 self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 10, 30, 2, 30, 0))
918 def test_split_form(self):
919 form = EventSplitForm({'dt_0': u'2011-09-01', 'dt_1': u'13:20:30'})
920 self.assertTrue(form.is_valid())
921 self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 9, 1, 13, 20, 30))
923 def test_model_form(self):
924 EventModelForm({'dt': u'2011-09-01 13:20:30'}).save()
925 e = Event.objects.get()
926 self.assertEqual(e.dt, datetime.datetime(2011, 9, 1, 13, 20, 30))
928 LegacyFormsTests = override_settings(DATETIME_FORMAT='c', USE_L10N=False, USE_TZ=False)(LegacyFormsTests)
930 #@override_settings(DATETIME_FORMAT='c', USE_L10N=False, USE_TZ=True)
931 class NewFormsTests(BaseDateTimeTests):
933 @requires_tz_support
934 def test_form(self):
935 form = EventForm({'dt': u'2011-09-01 13:20:30'})
936 self.assertTrue(form.is_valid())
937 self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC))
939 def test_form_with_other_timezone(self):
940 form = EventForm({'dt': u'2011-09-01 17:20:30'})
941 with timezone.override(ICT):
942 self.assertTrue(form.is_valid())
943 self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC))
945 @skipIf(pytz is None, "this test requires pytz")
946 def test_form_with_non_existent_time(self):
947 with timezone.override(pytz.timezone('Europe/Paris')):
948 form = EventForm({'dt': u'2011-03-27 02:30:00'})
949 self.assertFalse(form.is_valid())
950 self.assertEqual(form.errors['dt'],
951 [u"2011-03-27 02:30:00 couldn't be interpreted in time zone "
952 u"Europe/Paris; it may be ambiguous or it may not exist."])
954 @skipIf(pytz is None, "this test requires pytz")
955 def test_form_with_ambiguous_time(self):
956 with timezone.override(pytz.timezone('Europe/Paris')):
957 form = EventForm({'dt': u'2011-10-30 02:30:00'})
958 self.assertFalse(form.is_valid())
959 self.assertEqual(form.errors['dt'],
960 [u"2011-10-30 02:30:00 couldn't be interpreted in time zone "
961 u"Europe/Paris; it may be ambiguous or it may not exist."])
963 @requires_tz_support
964 def test_split_form(self):
965 form = EventSplitForm({'dt_0': u'2011-09-01', 'dt_1': u'13:20:30'})
966 self.assertTrue(form.is_valid())
967 self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC))
969 @requires_tz_support
970 def test_model_form(self):
971 EventModelForm({'dt': u'2011-09-01 13:20:30'}).save()
972 e = Event.objects.get()
973 self.assertEqual(e.dt, datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC))
975 NewFormsTests = override_settings(DATETIME_FORMAT='c', USE_L10N=False, USE_TZ=True)(NewFormsTests)
977 #@override_settings(DATETIME_FORMAT='c', USE_L10N=False, USE_TZ=True)
978 class AdminTests(BaseDateTimeTests):
980 urls = 'modeltests.timezones.urls'
981 fixtures = ['tz_users.xml']
983 def setUp(self):
984 self.client.login(username='super', password='secret')
986 @requires_tz_support
987 def test_changelist(self):
988 e = Event.objects.create(dt=datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC))
989 response = self.client.get(reverse('admin:timezones_event_changelist'))
990 self.assertContains(response, e.dt.astimezone(EAT).isoformat())
992 def test_changelist_in_other_timezone(self):
993 e = Event.objects.create(dt=datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC))
994 with timezone.override(ICT):
995 response = self.client.get(reverse('admin:timezones_event_changelist'))
996 self.assertContains(response, e.dt.astimezone(ICT).isoformat())
998 @requires_tz_support
999 def test_change_editable(self):
1000 e = Event.objects.create(dt=datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC))
1001 response = self.client.get(reverse('admin:timezones_event_change', args=(e.pk,)))
1002 self.assertContains(response, e.dt.astimezone(EAT).date().isoformat())
1003 self.assertContains(response, e.dt.astimezone(EAT).time().isoformat())
1005 def test_change_editable_in_other_timezone(self):
1006 e = Event.objects.create(dt=datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC))
1007 with timezone.override(ICT):
1008 response = self.client.get(reverse('admin:timezones_event_change', args=(e.pk,)))
1009 self.assertContains(response, e.dt.astimezone(ICT).date().isoformat())
1010 self.assertContains(response, e.dt.astimezone(ICT).time().isoformat())
1012 @requires_tz_support
1013 def test_change_readonly(self):
1014 Timestamp.objects.create()
1015 # re-fetch the object for backends that lose microseconds (MySQL)
1016 t = Timestamp.objects.get()
1017 response = self.client.get(reverse('admin:timezones_timestamp_change', args=(t.pk,)))
1018 self.assertContains(response, t.created.astimezone(EAT).isoformat())
1020 def test_change_readonly_in_other_timezone(self):
1021 Timestamp.objects.create()
1022 # re-fetch the object for backends that lose microseconds (MySQL)
1023 t = Timestamp.objects.get()
1024 with timezone.override(ICT):
1025 response = self.client.get(reverse('admin:timezones_timestamp_change', args=(t.pk,)))
1026 self.assertContains(response, t.created.astimezone(ICT).isoformat())
1028 AdminTests = override_settings(DATETIME_FORMAT='c', USE_L10N=False, USE_TZ=True)(AdminTests)
1031 class UtilitiesTests(BaseDateTimeTests):
1033 def test_make_aware(self):
1034 self.assertEqual(
1035 timezone.make_aware(datetime.datetime(2011, 9, 1, 13, 20, 30), EAT),
1036 datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
1038 self.assertEqual(
1039 timezone.make_aware(datetime.datetime(2011, 9, 1, 10, 20, 30), UTC),
1040 datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
1043 def test_make_naive(self):
1044 self.assertEqual(
1045 timezone.make_naive(datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT), EAT),
1046 datetime.datetime(2011, 9, 1, 13, 20, 30)
1048 self.assertEqual(
1049 timezone.make_naive(datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT), UTC),
1050 datetime.datetime(2011, 9, 1, 10, 20, 30)
1052 self.assertEqual(
1053 timezone.make_naive(datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC), UTC),
1054 datetime.datetime(2011, 9, 1, 10, 20, 30)