tests.py 53 KB

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