~ubuntu-branches/debian/sid/python-django/sid

« back to all changes in this revision

Viewing changes to tests/modeltests/timezones/tests.py

  • Committer: Package Import Robot
  • Author(s): Luke Faraone
  • Date: 2013-11-07 15:33:49 UTC
  • mfrom: (1.3.12)
  • Revision ID: package-import@ubuntu.com-20131107153349-e31sc149l2szs3jb
Tags: 1.6-1
* New upstream version. Closes: #557474, #724637.
* python-django now also suggests the installation of ipython,
  bpython, python-django-doc, and libgdal1.
  Closes: #636511, #686333, #704203
* Set package maintainer to Debian Python Modules Team.
* Bump standards version to 3.9.5, no changes needed.

Show diffs side-by-side

added added

removed removed

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