1. import datetime
    
  2. import re
    
  3. import sys
    
  4. from contextlib import contextmanager
    
  5. from unittest import SkipTest, skipIf
    
  6. from xml.dom.minidom import parseString
    
  7. 
    
  8. try:
    
  9.     import zoneinfo
    
  10. except ImportError:
    
  11.     from backports import zoneinfo
    
  12. 
    
  13. try:
    
  14.     import pytz
    
  15. except ImportError:
    
  16.     pytz = None
    
  17. 
    
  18. from django.contrib.auth.models import User
    
  19. from django.core import serializers
    
  20. from django.db import connection
    
  21. from django.db.models import F, Max, Min
    
  22. from django.http import HttpRequest
    
  23. from django.template import (
    
  24.     Context,
    
  25.     RequestContext,
    
  26.     Template,
    
  27.     TemplateSyntaxError,
    
  28.     context_processors,
    
  29. )
    
  30. from django.test import (
    
  31.     SimpleTestCase,
    
  32.     TestCase,
    
  33.     TransactionTestCase,
    
  34.     ignore_warnings,
    
  35.     override_settings,
    
  36.     skipIfDBFeature,
    
  37.     skipUnlessDBFeature,
    
  38. )
    
  39. from django.test.utils import requires_tz_support
    
  40. from django.urls import reverse
    
  41. from django.utils import timezone
    
  42. from django.utils.deprecation import RemovedInDjango50Warning
    
  43. from django.utils.timezone import timedelta
    
  44. 
    
  45. from .forms import (
    
  46.     EventForm,
    
  47.     EventLocalizedForm,
    
  48.     EventLocalizedModelForm,
    
  49.     EventModelForm,
    
  50.     EventSplitForm,
    
  51. )
    
  52. from .models import (
    
  53.     AllDayEvent,
    
  54.     DailyEvent,
    
  55.     Event,
    
  56.     MaybeEvent,
    
  57.     Session,
    
  58.     SessionEvent,
    
  59.     Timestamp,
    
  60. )
    
  61. 
    
  62. try:
    
  63.     import yaml
    
  64. 
    
  65.     HAS_YAML = True
    
  66. except ImportError:
    
  67.     HAS_YAML = False
    
  68. 
    
  69. # These tests use the EAT (Eastern Africa Time) and ICT (Indochina Time)
    
  70. # who don't have daylight saving time, so we can represent them easily
    
  71. # with fixed offset timezones and use them directly as tzinfo in the
    
  72. # constructors.
    
  73. 
    
  74. # settings.TIME_ZONE is forced to EAT. Most tests use a variant of
    
  75. # datetime.datetime(2011, 9, 1, 13, 20, 30), which translates to
    
  76. # 10:20:30 in UTC and 17:20:30 in ICT.
    
  77. 
    
  78. UTC = datetime.timezone.utc
    
  79. EAT = timezone.get_fixed_timezone(180)  # Africa/Nairobi
    
  80. ICT = timezone.get_fixed_timezone(420)  # Asia/Bangkok
    
  81. 
    
  82. ZONE_CONSTRUCTORS = (zoneinfo.ZoneInfo,)
    
  83. if pytz is not None:
    
  84.     ZONE_CONSTRUCTORS += (pytz.timezone,)
    
  85. 
    
  86. 
    
  87. def get_timezones(key):
    
  88.     return [constructor(key) for constructor in ZONE_CONSTRUCTORS]
    
  89. 
    
  90. 
    
  91. class UTCAliasTests(SimpleTestCase):
    
  92.     def test_alias_deprecation_warning(self):
    
  93.         msg = (
    
  94.             "The django.utils.timezone.utc alias is deprecated. "
    
  95.             "Please update your code to use datetime.timezone.utc instead."
    
  96.         )
    
  97.         with self.assertRaisesMessage(RemovedInDjango50Warning, msg):
    
  98.             timezone.utc
    
  99. 
    
  100.     def test_timezone_module_dir_includes_utc(self):
    
  101.         self.assertIn("utc", dir(timezone))
    
  102. 
    
  103. 
    
  104. @contextmanager
    
  105. def override_database_connection_timezone(timezone):
    
  106.     try:
    
  107.         orig_timezone = connection.settings_dict["TIME_ZONE"]
    
  108.         connection.settings_dict["TIME_ZONE"] = timezone
    
  109.         # Clear cached properties, after first accessing them to ensure they exist.
    
  110.         connection.timezone
    
  111.         del connection.timezone
    
  112.         connection.timezone_name
    
  113.         del connection.timezone_name
    
  114.         yield
    
  115.     finally:
    
  116.         connection.settings_dict["TIME_ZONE"] = orig_timezone
    
  117.         # Clear cached properties, after first accessing them to ensure they exist.
    
  118.         connection.timezone
    
  119.         del connection.timezone
    
  120.         connection.timezone_name
    
  121.         del connection.timezone_name
    
  122. 
    
  123. 
    
  124. @override_settings(TIME_ZONE="Africa/Nairobi", USE_TZ=False)
    
  125. class LegacyDatabaseTests(TestCase):
    
  126.     def test_naive_datetime(self):
    
  127.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
    
  128.         Event.objects.create(dt=dt)
    
  129.         event = Event.objects.get()
    
  130.         self.assertEqual(event.dt, dt)
    
  131. 
    
  132.     def test_naive_datetime_with_microsecond(self):
    
  133.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
    
  134.         Event.objects.create(dt=dt)
    
  135.         event = Event.objects.get()
    
  136.         self.assertEqual(event.dt, dt)
    
  137. 
    
  138.     @skipUnlessDBFeature("supports_timezones")
    
  139.     def test_aware_datetime_in_local_timezone(self):
    
  140.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
    
  141.         Event.objects.create(dt=dt)
    
  142.         event = Event.objects.get()
    
  143.         self.assertIsNone(event.dt.tzinfo)
    
  144.         # interpret the naive datetime in local time to get the correct value
    
  145.         self.assertEqual(event.dt.replace(tzinfo=EAT), dt)
    
  146. 
    
  147.     @skipUnlessDBFeature("supports_timezones")
    
  148.     def test_aware_datetime_in_local_timezone_with_microsecond(self):
    
  149.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
    
  150.         Event.objects.create(dt=dt)
    
  151.         event = Event.objects.get()
    
  152.         self.assertIsNone(event.dt.tzinfo)
    
  153.         # interpret the naive datetime in local time to get the correct value
    
  154.         self.assertEqual(event.dt.replace(tzinfo=EAT), dt)
    
  155. 
    
  156.     @skipUnlessDBFeature("supports_timezones")
    
  157.     def test_aware_datetime_in_utc(self):
    
  158.         dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
    
  159.         Event.objects.create(dt=dt)
    
  160.         event = Event.objects.get()
    
  161.         self.assertIsNone(event.dt.tzinfo)
    
  162.         # interpret the naive datetime in local time to get the correct value
    
  163.         self.assertEqual(event.dt.replace(tzinfo=EAT), dt)
    
  164. 
    
  165.     @skipUnlessDBFeature("supports_timezones")
    
  166.     def test_aware_datetime_in_other_timezone(self):
    
  167.         dt = datetime.datetime(2011, 9, 1, 17, 20, 30, tzinfo=ICT)
    
  168.         Event.objects.create(dt=dt)
    
  169.         event = Event.objects.get()
    
  170.         self.assertIsNone(event.dt.tzinfo)
    
  171.         # interpret the naive datetime in local time to get the correct value
    
  172.         self.assertEqual(event.dt.replace(tzinfo=EAT), dt)
    
  173. 
    
  174.     @skipIfDBFeature("supports_timezones")
    
  175.     def test_aware_datetime_unsupported(self):
    
  176.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
    
  177.         msg = "backend does not support timezone-aware datetimes when USE_TZ is False."
    
  178.         with self.assertRaisesMessage(ValueError, msg):
    
  179.             Event.objects.create(dt=dt)
    
  180. 
    
  181.     def test_auto_now_and_auto_now_add(self):
    
  182.         now = datetime.datetime.now()
    
  183.         past = now - datetime.timedelta(seconds=2)
    
  184.         future = now + datetime.timedelta(seconds=2)
    
  185.         Timestamp.objects.create()
    
  186.         ts = Timestamp.objects.get()
    
  187.         self.assertLess(past, ts.created)
    
  188.         self.assertLess(past, ts.updated)
    
  189.         self.assertGreater(future, ts.updated)
    
  190.         self.assertGreater(future, ts.updated)
    
  191. 
    
  192.     def test_query_filter(self):
    
  193.         dt1 = datetime.datetime(2011, 9, 1, 12, 20, 30)
    
  194.         dt2 = datetime.datetime(2011, 9, 1, 14, 20, 30)
    
  195.         Event.objects.create(dt=dt1)
    
  196.         Event.objects.create(dt=dt2)
    
  197.         self.assertEqual(Event.objects.filter(dt__gte=dt1).count(), 2)
    
  198.         self.assertEqual(Event.objects.filter(dt__gt=dt1).count(), 1)
    
  199.         self.assertEqual(Event.objects.filter(dt__gte=dt2).count(), 1)
    
  200.         self.assertEqual(Event.objects.filter(dt__gt=dt2).count(), 0)
    
  201. 
    
  202.     def test_query_datetime_lookups(self):
    
  203.         Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0))
    
  204.         Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0))
    
  205.         self.assertEqual(Event.objects.filter(dt__year=2011).count(), 2)
    
  206.         self.assertEqual(Event.objects.filter(dt__month=1).count(), 2)
    
  207.         self.assertEqual(Event.objects.filter(dt__day=1).count(), 2)
    
  208.         self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 2)
    
  209.         self.assertEqual(Event.objects.filter(dt__iso_week_day=6).count(), 2)
    
  210.         self.assertEqual(Event.objects.filter(dt__hour=1).count(), 1)
    
  211.         self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2)
    
  212.         self.assertEqual(Event.objects.filter(dt__second=0).count(), 2)
    
  213. 
    
  214.     def test_query_aggregation(self):
    
  215.         # Only min and max make sense for datetimes.
    
  216.         Event.objects.create(dt=datetime.datetime(2011, 9, 1, 23, 20, 20))
    
  217.         Event.objects.create(dt=datetime.datetime(2011, 9, 1, 13, 20, 30))
    
  218.         Event.objects.create(dt=datetime.datetime(2011, 9, 1, 3, 20, 40))
    
  219.         result = Event.objects.aggregate(Min("dt"), Max("dt"))
    
  220.         self.assertEqual(
    
  221.             result,
    
  222.             {
    
  223.                 "dt__min": datetime.datetime(2011, 9, 1, 3, 20, 40),
    
  224.                 "dt__max": datetime.datetime(2011, 9, 1, 23, 20, 20),
    
  225.             },
    
  226.         )
    
  227. 
    
  228.     def test_query_annotation(self):
    
  229.         # Only min and max make sense for datetimes.
    
  230.         morning = Session.objects.create(name="morning")
    
  231.         afternoon = Session.objects.create(name="afternoon")
    
  232.         SessionEvent.objects.create(
    
  233.             dt=datetime.datetime(2011, 9, 1, 23, 20, 20), session=afternoon
    
  234.         )
    
  235.         SessionEvent.objects.create(
    
  236.             dt=datetime.datetime(2011, 9, 1, 13, 20, 30), session=afternoon
    
  237.         )
    
  238.         SessionEvent.objects.create(
    
  239.             dt=datetime.datetime(2011, 9, 1, 3, 20, 40), session=morning
    
  240.         )
    
  241.         morning_min_dt = datetime.datetime(2011, 9, 1, 3, 20, 40)
    
  242.         afternoon_min_dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
    
  243.         self.assertQuerysetEqual(
    
  244.             Session.objects.annotate(dt=Min("events__dt")).order_by("dt"),
    
  245.             [morning_min_dt, afternoon_min_dt],
    
  246.             transform=lambda d: d.dt,
    
  247.         )
    
  248.         self.assertQuerysetEqual(
    
  249.             Session.objects.annotate(dt=Min("events__dt")).filter(
    
  250.                 dt__lt=afternoon_min_dt
    
  251.             ),
    
  252.             [morning_min_dt],
    
  253.             transform=lambda d: d.dt,
    
  254.         )
    
  255.         self.assertQuerysetEqual(
    
  256.             Session.objects.annotate(dt=Min("events__dt")).filter(
    
  257.                 dt__gte=afternoon_min_dt
    
  258.             ),
    
  259.             [afternoon_min_dt],
    
  260.             transform=lambda d: d.dt,
    
  261.         )
    
  262. 
    
  263.     def test_query_datetimes(self):
    
  264.         Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0))
    
  265.         Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0))
    
  266.         self.assertSequenceEqual(
    
  267.             Event.objects.datetimes("dt", "year"),
    
  268.             [datetime.datetime(2011, 1, 1, 0, 0, 0)],
    
  269.         )
    
  270.         self.assertSequenceEqual(
    
  271.             Event.objects.datetimes("dt", "month"),
    
  272.             [datetime.datetime(2011, 1, 1, 0, 0, 0)],
    
  273.         )
    
  274.         self.assertSequenceEqual(
    
  275.             Event.objects.datetimes("dt", "day"),
    
  276.             [datetime.datetime(2011, 1, 1, 0, 0, 0)],
    
  277.         )
    
  278.         self.assertSequenceEqual(
    
  279.             Event.objects.datetimes("dt", "hour"),
    
  280.             [
    
  281.                 datetime.datetime(2011, 1, 1, 1, 0, 0),
    
  282.                 datetime.datetime(2011, 1, 1, 4, 0, 0),
    
  283.             ],
    
  284.         )
    
  285.         self.assertSequenceEqual(
    
  286.             Event.objects.datetimes("dt", "minute"),
    
  287.             [
    
  288.                 datetime.datetime(2011, 1, 1, 1, 30, 0),
    
  289.                 datetime.datetime(2011, 1, 1, 4, 30, 0),
    
  290.             ],
    
  291.         )
    
  292.         self.assertSequenceEqual(
    
  293.             Event.objects.datetimes("dt", "second"),
    
  294.             [
    
  295.                 datetime.datetime(2011, 1, 1, 1, 30, 0),
    
  296.                 datetime.datetime(2011, 1, 1, 4, 30, 0),
    
  297.             ],
    
  298.         )
    
  299. 
    
  300.     def test_raw_sql(self):
    
  301.         # Regression test for #17755
    
  302.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
    
  303.         event = Event.objects.create(dt=dt)
    
  304.         self.assertEqual(
    
  305.             list(
    
  306.                 Event.objects.raw("SELECT * FROM timezones_event WHERE dt = %s", [dt])
    
  307.             ),
    
  308.             [event],
    
  309.         )
    
  310. 
    
  311.     def test_cursor_execute_accepts_naive_datetime(self):
    
  312.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
    
  313.         with connection.cursor() as cursor:
    
  314.             cursor.execute("INSERT INTO timezones_event (dt) VALUES (%s)", [dt])
    
  315.         event = Event.objects.get()
    
  316.         self.assertEqual(event.dt, dt)
    
  317. 
    
  318.     def test_cursor_execute_returns_naive_datetime(self):
    
  319.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
    
  320.         Event.objects.create(dt=dt)
    
  321.         with connection.cursor() as cursor:
    
  322.             cursor.execute("SELECT dt FROM timezones_event WHERE dt = %s", [dt])
    
  323.             self.assertEqual(cursor.fetchall()[0][0], dt)
    
  324. 
    
  325.     def test_filter_date_field_with_aware_datetime(self):
    
  326.         # Regression test for #17742
    
  327.         day = datetime.date(2011, 9, 1)
    
  328.         AllDayEvent.objects.create(day=day)
    
  329.         # This is 2011-09-02T01:30:00+03:00 in EAT
    
  330.         dt = datetime.datetime(2011, 9, 1, 22, 30, 0, tzinfo=UTC)
    
  331.         self.assertTrue(AllDayEvent.objects.filter(day__gte=dt).exists())
    
  332. 
    
  333. 
    
  334. @override_settings(TIME_ZONE="Africa/Nairobi", USE_TZ=True)
    
  335. class NewDatabaseTests(TestCase):
    
  336.     naive_warning = "DateTimeField Event.dt received a naive datetime"
    
  337. 
    
  338.     @skipIfDBFeature("supports_timezones")
    
  339.     def test_aware_time_unsupported(self):
    
  340.         t = datetime.time(13, 20, 30, tzinfo=EAT)
    
  341.         msg = "backend does not support timezone-aware times."
    
  342.         with self.assertRaisesMessage(ValueError, msg):
    
  343.             DailyEvent.objects.create(time=t)
    
  344. 
    
  345.     @requires_tz_support
    
  346.     def test_naive_datetime(self):
    
  347.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
    
  348.         with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
    
  349.             Event.objects.create(dt=dt)
    
  350.         event = Event.objects.get()
    
  351.         # naive datetimes are interpreted in local time
    
  352.         self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
    
  353. 
    
  354.     @requires_tz_support
    
  355.     def test_datetime_from_date(self):
    
  356.         dt = datetime.date(2011, 9, 1)
    
  357.         with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
    
  358.             Event.objects.create(dt=dt)
    
  359.         event = Event.objects.get()
    
  360.         self.assertEqual(event.dt, datetime.datetime(2011, 9, 1, tzinfo=EAT))
    
  361. 
    
  362.     @requires_tz_support
    
  363.     def test_naive_datetime_with_microsecond(self):
    
  364.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
    
  365.         with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
    
  366.             Event.objects.create(dt=dt)
    
  367.         event = Event.objects.get()
    
  368.         # naive datetimes are interpreted in local time
    
  369.         self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
    
  370. 
    
  371.     def test_aware_datetime_in_local_timezone(self):
    
  372.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
    
  373.         Event.objects.create(dt=dt)
    
  374.         event = Event.objects.get()
    
  375.         self.assertEqual(event.dt, dt)
    
  376. 
    
  377.     def test_aware_datetime_in_local_timezone_with_microsecond(self):
    
  378.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060, tzinfo=EAT)
    
  379.         Event.objects.create(dt=dt)
    
  380.         event = Event.objects.get()
    
  381.         self.assertEqual(event.dt, dt)
    
  382. 
    
  383.     def test_aware_datetime_in_utc(self):
    
  384.         dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
    
  385.         Event.objects.create(dt=dt)
    
  386.         event = Event.objects.get()
    
  387.         self.assertEqual(event.dt, dt)
    
  388. 
    
  389.     def test_aware_datetime_in_other_timezone(self):
    
  390.         dt = datetime.datetime(2011, 9, 1, 17, 20, 30, tzinfo=ICT)
    
  391.         Event.objects.create(dt=dt)
    
  392.         event = Event.objects.get()
    
  393.         self.assertEqual(event.dt, dt)
    
  394. 
    
  395.     def test_auto_now_and_auto_now_add(self):
    
  396.         now = timezone.now()
    
  397.         past = now - datetime.timedelta(seconds=2)
    
  398.         future = now + datetime.timedelta(seconds=2)
    
  399.         Timestamp.objects.create()
    
  400.         ts = Timestamp.objects.get()
    
  401.         self.assertLess(past, ts.created)
    
  402.         self.assertLess(past, ts.updated)
    
  403.         self.assertGreater(future, ts.updated)
    
  404.         self.assertGreater(future, ts.updated)
    
  405. 
    
  406.     def test_query_filter(self):
    
  407.         dt1 = datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=EAT)
    
  408.         dt2 = datetime.datetime(2011, 9, 1, 14, 20, 30, tzinfo=EAT)
    
  409.         Event.objects.create(dt=dt1)
    
  410.         Event.objects.create(dt=dt2)
    
  411.         self.assertEqual(Event.objects.filter(dt__gte=dt1).count(), 2)
    
  412.         self.assertEqual(Event.objects.filter(dt__gt=dt1).count(), 1)
    
  413.         self.assertEqual(Event.objects.filter(dt__gte=dt2).count(), 1)
    
  414.         self.assertEqual(Event.objects.filter(dt__gt=dt2).count(), 0)
    
  415. 
    
  416.     def test_query_filter_with_pytz_timezones(self):
    
  417.         for tz in get_timezones("Europe/Paris"):
    
  418.             with self.subTest(repr(tz)):
    
  419.                 dt = datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=tz)
    
  420.                 Event.objects.create(dt=dt)
    
  421.                 next = dt + datetime.timedelta(seconds=3)
    
  422.                 prev = dt - datetime.timedelta(seconds=3)
    
  423.                 self.assertEqual(Event.objects.filter(dt__exact=dt).count(), 1)
    
  424.                 self.assertEqual(Event.objects.filter(dt__exact=next).count(), 0)
    
  425.                 self.assertEqual(Event.objects.filter(dt__in=(prev, next)).count(), 0)
    
  426.                 self.assertEqual(
    
  427.                     Event.objects.filter(dt__in=(prev, dt, next)).count(), 1
    
  428.                 )
    
  429.                 self.assertEqual(
    
  430.                     Event.objects.filter(dt__range=(prev, next)).count(), 1
    
  431.                 )
    
  432. 
    
  433.     @ignore_warnings(category=RemovedInDjango50Warning)
    
  434.     def test_connection_timezone(self):
    
  435.         tests = [
    
  436.             (False, None, datetime.timezone),
    
  437.             (False, "Africa/Nairobi", zoneinfo.ZoneInfo),
    
  438.         ]
    
  439.         if pytz is not None:
    
  440.             tests += [
    
  441.                 (True, None, datetime.timezone),
    
  442.                 (True, "Africa/Nairobi", pytz.BaseTzInfo),
    
  443.             ]
    
  444.         for use_pytz, connection_tz, expected_type in tests:
    
  445.             with self.subTest(use_pytz=use_pytz, connection_tz=connection_tz):
    
  446.                 with self.settings(USE_DEPRECATED_PYTZ=use_pytz):
    
  447.                     with override_database_connection_timezone(connection_tz):
    
  448.                         self.assertIsInstance(connection.timezone, expected_type)
    
  449. 
    
  450.     def test_query_convert_timezones(self):
    
  451.         # Connection timezone is equal to the current timezone, datetime
    
  452.         # shouldn't be converted.
    
  453.         with override_database_connection_timezone("Africa/Nairobi"):
    
  454.             event_datetime = datetime.datetime(2016, 1, 2, 23, 10, 11, 123, tzinfo=EAT)
    
  455.             event = Event.objects.create(dt=event_datetime)
    
  456.             self.assertEqual(
    
  457.                 Event.objects.filter(dt__date=event_datetime.date()).first(), event
    
  458.             )
    
  459.         # Connection timezone is not equal to the current timezone, datetime
    
  460.         # should be converted (-4h).
    
  461.         with override_database_connection_timezone("Asia/Bangkok"):
    
  462.             event_datetime = datetime.datetime(2016, 1, 2, 3, 10, 11, tzinfo=ICT)
    
  463.             event = Event.objects.create(dt=event_datetime)
    
  464.             self.assertEqual(
    
  465.                 Event.objects.filter(dt__date=datetime.date(2016, 1, 1)).first(), event
    
  466.             )
    
  467. 
    
  468.     @requires_tz_support
    
  469.     def test_query_filter_with_naive_datetime(self):
    
  470.         dt = datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=EAT)
    
  471.         Event.objects.create(dt=dt)
    
  472.         dt = dt.replace(tzinfo=None)
    
  473.         # naive datetimes are interpreted in local time
    
  474.         with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
    
  475.             self.assertEqual(Event.objects.filter(dt__exact=dt).count(), 1)
    
  476.         with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
    
  477.             self.assertEqual(Event.objects.filter(dt__lte=dt).count(), 1)
    
  478.         with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
    
  479.             self.assertEqual(Event.objects.filter(dt__gt=dt).count(), 0)
    
  480. 
    
  481.     @skipUnlessDBFeature("has_zoneinfo_database")
    
  482.     def test_query_datetime_lookups(self):
    
  483.         Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=EAT))
    
  484.         Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0, tzinfo=EAT))
    
  485.         self.assertEqual(Event.objects.filter(dt__year=2011).count(), 2)
    
  486.         self.assertEqual(Event.objects.filter(dt__month=1).count(), 2)
    
  487.         self.assertEqual(Event.objects.filter(dt__day=1).count(), 2)
    
  488.         self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 2)
    
  489.         self.assertEqual(Event.objects.filter(dt__iso_week_day=6).count(), 2)
    
  490.         self.assertEqual(Event.objects.filter(dt__hour=1).count(), 1)
    
  491.         self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2)
    
  492.         self.assertEqual(Event.objects.filter(dt__second=0).count(), 2)
    
  493. 
    
  494.     @skipUnlessDBFeature("has_zoneinfo_database")
    
  495.     def test_query_datetime_lookups_in_other_timezone(self):
    
  496.         Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=EAT))
    
  497.         Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0, tzinfo=EAT))
    
  498.         with timezone.override(UTC):
    
  499.             # These two dates fall in the same day in EAT, but in different days,
    
  500.             # years and months in UTC.
    
  501.             self.assertEqual(Event.objects.filter(dt__year=2011).count(), 1)
    
  502.             self.assertEqual(Event.objects.filter(dt__month=1).count(), 1)
    
  503.             self.assertEqual(Event.objects.filter(dt__day=1).count(), 1)
    
  504.             self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 1)
    
  505.             self.assertEqual(Event.objects.filter(dt__iso_week_day=6).count(), 1)
    
  506.             self.assertEqual(Event.objects.filter(dt__hour=22).count(), 1)
    
  507.             self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2)
    
  508.             self.assertEqual(Event.objects.filter(dt__second=0).count(), 2)
    
  509. 
    
  510.     def test_query_aggregation(self):
    
  511.         # Only min and max make sense for datetimes.
    
  512.         Event.objects.create(dt=datetime.datetime(2011, 9, 1, 23, 20, 20, tzinfo=EAT))
    
  513.         Event.objects.create(dt=datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT))
    
  514.         Event.objects.create(dt=datetime.datetime(2011, 9, 1, 3, 20, 40, tzinfo=EAT))
    
  515.         result = Event.objects.aggregate(Min("dt"), Max("dt"))
    
  516.         self.assertEqual(
    
  517.             result,
    
  518.             {
    
  519.                 "dt__min": datetime.datetime(2011, 9, 1, 3, 20, 40, tzinfo=EAT),
    
  520.                 "dt__max": datetime.datetime(2011, 9, 1, 23, 20, 20, tzinfo=EAT),
    
  521.             },
    
  522.         )
    
  523. 
    
  524.     def test_query_annotation(self):
    
  525.         # Only min and max make sense for datetimes.
    
  526.         morning = Session.objects.create(name="morning")
    
  527.         afternoon = Session.objects.create(name="afternoon")
    
  528.         SessionEvent.objects.create(
    
  529.             dt=datetime.datetime(2011, 9, 1, 23, 20, 20, tzinfo=EAT), session=afternoon
    
  530.         )
    
  531.         SessionEvent.objects.create(
    
  532.             dt=datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT), session=afternoon
    
  533.         )
    
  534.         SessionEvent.objects.create(
    
  535.             dt=datetime.datetime(2011, 9, 1, 3, 20, 40, tzinfo=EAT), session=morning
    
  536.         )
    
  537.         morning_min_dt = datetime.datetime(2011, 9, 1, 3, 20, 40, tzinfo=EAT)
    
  538.         afternoon_min_dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
    
  539.         self.assertQuerysetEqual(
    
  540.             Session.objects.annotate(dt=Min("events__dt")).order_by("dt"),
    
  541.             [morning_min_dt, afternoon_min_dt],
    
  542.             transform=lambda d: d.dt,
    
  543.         )
    
  544.         self.assertQuerysetEqual(
    
  545.             Session.objects.annotate(dt=Min("events__dt")).filter(
    
  546.                 dt__lt=afternoon_min_dt
    
  547.             ),
    
  548.             [morning_min_dt],
    
  549.             transform=lambda d: d.dt,
    
  550.         )
    
  551.         self.assertQuerysetEqual(
    
  552.             Session.objects.annotate(dt=Min("events__dt")).filter(
    
  553.                 dt__gte=afternoon_min_dt
    
  554.             ),
    
  555.             [afternoon_min_dt],
    
  556.             transform=lambda d: d.dt,
    
  557.         )
    
  558. 
    
  559.     @skipUnlessDBFeature("has_zoneinfo_database")
    
  560.     def test_query_datetimes(self):
    
  561.         Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=EAT))
    
  562.         Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0, tzinfo=EAT))
    
  563.         self.assertSequenceEqual(
    
  564.             Event.objects.datetimes("dt", "year"),
    
  565.             [datetime.datetime(2011, 1, 1, 0, 0, 0, tzinfo=EAT)],
    
  566.         )
    
  567.         self.assertSequenceEqual(
    
  568.             Event.objects.datetimes("dt", "month"),
    
  569.             [datetime.datetime(2011, 1, 1, 0, 0, 0, tzinfo=EAT)],
    
  570.         )
    
  571.         self.assertSequenceEqual(
    
  572.             Event.objects.datetimes("dt", "day"),
    
  573.             [datetime.datetime(2011, 1, 1, 0, 0, 0, tzinfo=EAT)],
    
  574.         )
    
  575.         self.assertSequenceEqual(
    
  576.             Event.objects.datetimes("dt", "hour"),
    
  577.             [
    
  578.                 datetime.datetime(2011, 1, 1, 1, 0, 0, tzinfo=EAT),
    
  579.                 datetime.datetime(2011, 1, 1, 4, 0, 0, tzinfo=EAT),
    
  580.             ],
    
  581.         )
    
  582.         self.assertSequenceEqual(
    
  583.             Event.objects.datetimes("dt", "minute"),
    
  584.             [
    
  585.                 datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=EAT),
    
  586.                 datetime.datetime(2011, 1, 1, 4, 30, 0, tzinfo=EAT),
    
  587.             ],
    
  588.         )
    
  589.         self.assertSequenceEqual(
    
  590.             Event.objects.datetimes("dt", "second"),
    
  591.             [
    
  592.                 datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=EAT),
    
  593.                 datetime.datetime(2011, 1, 1, 4, 30, 0, tzinfo=EAT),
    
  594.             ],
    
  595.         )
    
  596. 
    
  597.     @skipUnlessDBFeature("has_zoneinfo_database")
    
  598.     def test_query_datetimes_in_other_timezone(self):
    
  599.         Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=EAT))
    
  600.         Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0, tzinfo=EAT))
    
  601.         with timezone.override(UTC):
    
  602.             self.assertSequenceEqual(
    
  603.                 Event.objects.datetimes("dt", "year"),
    
  604.                 [
    
  605.                     datetime.datetime(2010, 1, 1, 0, 0, 0, tzinfo=UTC),
    
  606.                     datetime.datetime(2011, 1, 1, 0, 0, 0, tzinfo=UTC),
    
  607.                 ],
    
  608.             )
    
  609.             self.assertSequenceEqual(
    
  610.                 Event.objects.datetimes("dt", "month"),
    
  611.                 [
    
  612.                     datetime.datetime(2010, 12, 1, 0, 0, 0, tzinfo=UTC),
    
  613.                     datetime.datetime(2011, 1, 1, 0, 0, 0, tzinfo=UTC),
    
  614.                 ],
    
  615.             )
    
  616.             self.assertSequenceEqual(
    
  617.                 Event.objects.datetimes("dt", "day"),
    
  618.                 [
    
  619.                     datetime.datetime(2010, 12, 31, 0, 0, 0, tzinfo=UTC),
    
  620.                     datetime.datetime(2011, 1, 1, 0, 0, 0, tzinfo=UTC),
    
  621.                 ],
    
  622.             )
    
  623.             self.assertSequenceEqual(
    
  624.                 Event.objects.datetimes("dt", "hour"),
    
  625.                 [
    
  626.                     datetime.datetime(2010, 12, 31, 22, 0, 0, tzinfo=UTC),
    
  627.                     datetime.datetime(2011, 1, 1, 1, 0, 0, tzinfo=UTC),
    
  628.                 ],
    
  629.             )
    
  630.             self.assertSequenceEqual(
    
  631.                 Event.objects.datetimes("dt", "minute"),
    
  632.                 [
    
  633.                     datetime.datetime(2010, 12, 31, 22, 30, 0, tzinfo=UTC),
    
  634.                     datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=UTC),
    
  635.                 ],
    
  636.             )
    
  637.             self.assertSequenceEqual(
    
  638.                 Event.objects.datetimes("dt", "second"),
    
  639.                 [
    
  640.                     datetime.datetime(2010, 12, 31, 22, 30, 0, tzinfo=UTC),
    
  641.                     datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=UTC),
    
  642.                 ],
    
  643.             )
    
  644. 
    
  645.     def test_raw_sql(self):
    
  646.         # Regression test for #17755
    
  647.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
    
  648.         event = Event.objects.create(dt=dt)
    
  649.         self.assertSequenceEqual(
    
  650.             list(
    
  651.                 Event.objects.raw("SELECT * FROM timezones_event WHERE dt = %s", [dt])
    
  652.             ),
    
  653.             [event],
    
  654.         )
    
  655. 
    
  656.     @skipUnlessDBFeature("supports_timezones")
    
  657.     def test_cursor_execute_accepts_aware_datetime(self):
    
  658.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
    
  659.         with connection.cursor() as cursor:
    
  660.             cursor.execute("INSERT INTO timezones_event (dt) VALUES (%s)", [dt])
    
  661.         event = Event.objects.get()
    
  662.         self.assertEqual(event.dt, dt)
    
  663. 
    
  664.     @skipIfDBFeature("supports_timezones")
    
  665.     def test_cursor_execute_accepts_naive_datetime(self):
    
  666.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
    
  667.         utc_naive_dt = timezone.make_naive(dt, datetime.timezone.utc)
    
  668.         with connection.cursor() as cursor:
    
  669.             cursor.execute(
    
  670.                 "INSERT INTO timezones_event (dt) VALUES (%s)", [utc_naive_dt]
    
  671.             )
    
  672.         event = Event.objects.get()
    
  673.         self.assertEqual(event.dt, dt)
    
  674. 
    
  675.     @skipUnlessDBFeature("supports_timezones")
    
  676.     def test_cursor_execute_returns_aware_datetime(self):
    
  677.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
    
  678.         Event.objects.create(dt=dt)
    
  679.         with connection.cursor() as cursor:
    
  680.             cursor.execute("SELECT dt FROM timezones_event WHERE dt = %s", [dt])
    
  681.             self.assertEqual(cursor.fetchall()[0][0], dt)
    
  682. 
    
  683.     @skipIfDBFeature("supports_timezones")
    
  684.     def test_cursor_execute_returns_naive_datetime(self):
    
  685.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
    
  686.         utc_naive_dt = timezone.make_naive(dt, datetime.timezone.utc)
    
  687.         Event.objects.create(dt=dt)
    
  688.         with connection.cursor() as cursor:
    
  689.             cursor.execute(
    
  690.                 "SELECT dt FROM timezones_event WHERE dt = %s", [utc_naive_dt]
    
  691.             )
    
  692.             self.assertEqual(cursor.fetchall()[0][0], utc_naive_dt)
    
  693. 
    
  694.     @skipUnlessDBFeature("supports_timezones")
    
  695.     def test_cursor_explicit_time_zone(self):
    
  696.         with override_database_connection_timezone("Europe/Paris"):
    
  697.             with connection.cursor() as cursor:
    
  698.                 cursor.execute("SELECT CURRENT_TIMESTAMP")
    
  699.                 now = cursor.fetchone()[0]
    
  700.                 self.assertEqual(str(now.tzinfo), "Europe/Paris")
    
  701. 
    
  702.     @requires_tz_support
    
  703.     def test_filter_date_field_with_aware_datetime(self):
    
  704.         # Regression test for #17742
    
  705.         day = datetime.date(2011, 9, 1)
    
  706.         AllDayEvent.objects.create(day=day)
    
  707.         # This is 2011-09-02T01:30:00+03:00 in EAT
    
  708.         dt = datetime.datetime(2011, 9, 1, 22, 30, 0, tzinfo=UTC)
    
  709.         self.assertFalse(AllDayEvent.objects.filter(day__gte=dt).exists())
    
  710. 
    
  711.     def test_null_datetime(self):
    
  712.         # Regression test for #17294
    
  713.         e = MaybeEvent.objects.create()
    
  714.         self.assertIsNone(e.dt)
    
  715. 
    
  716.     def test_update_with_timedelta(self):
    
  717.         initial_dt = timezone.now().replace(microsecond=0)
    
  718.         event = Event.objects.create(dt=initial_dt)
    
  719.         Event.objects.update(dt=F("dt") + timedelta(hours=2))
    
  720.         event.refresh_from_db()
    
  721.         self.assertEqual(event.dt, initial_dt + timedelta(hours=2))
    
  722. 
    
  723. 
    
  724. @override_settings(TIME_ZONE="Africa/Nairobi", USE_TZ=True)
    
  725. class ForcedTimeZoneDatabaseTests(TransactionTestCase):
    
  726.     """
    
  727.     Test the TIME_ZONE database configuration parameter.
    
  728. 
    
  729.     Since this involves reading and writing to the same database through two
    
  730.     connections, this is a TransactionTestCase.
    
  731.     """
    
  732. 
    
  733.     available_apps = ["timezones"]
    
  734. 
    
  735.     @classmethod
    
  736.     def setUpClass(cls):
    
  737.         # @skipIfDBFeature and @skipUnlessDBFeature cannot be chained. The
    
  738.         # outermost takes precedence. Handle skipping manually instead.
    
  739.         if connection.features.supports_timezones:
    
  740.             raise SkipTest("Database has feature(s) supports_timezones")
    
  741.         if not connection.features.test_db_allows_multiple_connections:
    
  742.             raise SkipTest(
    
  743.                 "Database doesn't support feature(s): "
    
  744.                 "test_db_allows_multiple_connections"
    
  745.             )
    
  746. 
    
  747.         super().setUpClass()
    
  748. 
    
  749.     def test_read_datetime(self):
    
  750.         fake_dt = datetime.datetime(2011, 9, 1, 17, 20, 30, tzinfo=UTC)
    
  751.         Event.objects.create(dt=fake_dt)
    
  752. 
    
  753.         with override_database_connection_timezone("Asia/Bangkok"):
    
  754.             event = Event.objects.get()
    
  755.             dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
    
  756.         self.assertEqual(event.dt, dt)
    
  757. 
    
  758.     def test_write_datetime(self):
    
  759.         dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
    
  760.         with override_database_connection_timezone("Asia/Bangkok"):
    
  761.             Event.objects.create(dt=dt)
    
  762. 
    
  763.         event = Event.objects.get()
    
  764.         fake_dt = datetime.datetime(2011, 9, 1, 17, 20, 30, tzinfo=UTC)
    
  765.         self.assertEqual(event.dt, fake_dt)
    
  766. 
    
  767. 
    
  768. @override_settings(TIME_ZONE="Africa/Nairobi")
    
  769. class SerializationTests(SimpleTestCase):
    
  770.     # Backend-specific notes:
    
  771.     # - JSON supports only milliseconds, microseconds will be truncated.
    
  772.     # - PyYAML dumps the UTC offset correctly for timezone-aware datetimes.
    
  773.     #   When PyYAML < 5.3 loads this representation, it subtracts the offset
    
  774.     #   and returns a naive datetime object in UTC. PyYAML 5.3+ loads timezones
    
  775.     #   correctly.
    
  776.     # Tests are adapted to take these quirks into account.
    
  777. 
    
  778.     def assert_python_contains_datetime(self, objects, dt):
    
  779.         self.assertEqual(objects[0]["fields"]["dt"], dt)
    
  780. 
    
  781.     def assert_json_contains_datetime(self, json, dt):
    
  782.         self.assertIn('"fields": {"dt": "%s"}' % dt, json)
    
  783. 
    
  784.     def assert_xml_contains_datetime(self, xml, dt):
    
  785.         field = parseString(xml).getElementsByTagName("field")[0]
    
  786.         self.assertXMLEqual(field.childNodes[0].wholeText, dt)
    
  787. 
    
  788.     def assert_yaml_contains_datetime(self, yaml, dt):
    
  789.         # Depending on the yaml dumper, '!timestamp' might be absent
    
  790.         self.assertRegex(yaml, r"\n  fields: {dt: !(!timestamp)? '%s'}" % re.escape(dt))
    
  791. 
    
  792.     def test_naive_datetime(self):
    
  793.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
    
  794. 
    
  795.         data = serializers.serialize("python", [Event(dt=dt)])
    
  796.         self.assert_python_contains_datetime(data, dt)
    
  797.         obj = next(serializers.deserialize("python", data)).object
    
  798.         self.assertEqual(obj.dt, dt)
    
  799. 
    
  800.         data = serializers.serialize("json", [Event(dt=dt)])
    
  801.         self.assert_json_contains_datetime(data, "2011-09-01T13:20:30")
    
  802.         obj = next(serializers.deserialize("json", data)).object
    
  803.         self.assertEqual(obj.dt, dt)
    
  804. 
    
  805.         data = serializers.serialize("xml", [Event(dt=dt)])
    
  806.         self.assert_xml_contains_datetime(data, "2011-09-01T13:20:30")
    
  807.         obj = next(serializers.deserialize("xml", data)).object
    
  808.         self.assertEqual(obj.dt, dt)
    
  809. 
    
  810.         if not isinstance(
    
  811.             serializers.get_serializer("yaml"), serializers.BadSerializer
    
  812.         ):
    
  813.             data = serializers.serialize(
    
  814.                 "yaml", [Event(dt=dt)], default_flow_style=None
    
  815.             )
    
  816.             self.assert_yaml_contains_datetime(data, "2011-09-01 13:20:30")
    
  817.             obj = next(serializers.deserialize("yaml", data)).object
    
  818.             self.assertEqual(obj.dt, dt)
    
  819. 
    
  820.     def test_naive_datetime_with_microsecond(self):
    
  821.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
    
  822. 
    
  823.         data = serializers.serialize("python", [Event(dt=dt)])
    
  824.         self.assert_python_contains_datetime(data, dt)
    
  825.         obj = next(serializers.deserialize("python", data)).object
    
  826.         self.assertEqual(obj.dt, dt)
    
  827. 
    
  828.         data = serializers.serialize("json", [Event(dt=dt)])
    
  829.         self.assert_json_contains_datetime(data, "2011-09-01T13:20:30.405")
    
  830.         obj = next(serializers.deserialize("json", data)).object
    
  831.         self.assertEqual(obj.dt, dt.replace(microsecond=405000))
    
  832. 
    
  833.         data = serializers.serialize("xml", [Event(dt=dt)])
    
  834.         self.assert_xml_contains_datetime(data, "2011-09-01T13:20:30.405060")
    
  835.         obj = next(serializers.deserialize("xml", data)).object
    
  836.         self.assertEqual(obj.dt, dt)
    
  837. 
    
  838.         if not isinstance(
    
  839.             serializers.get_serializer("yaml"), serializers.BadSerializer
    
  840.         ):
    
  841.             data = serializers.serialize(
    
  842.                 "yaml", [Event(dt=dt)], default_flow_style=None
    
  843.             )
    
  844.             self.assert_yaml_contains_datetime(data, "2011-09-01 13:20:30.405060")
    
  845.             obj = next(serializers.deserialize("yaml", data)).object
    
  846.             self.assertEqual(obj.dt, dt)
    
  847. 
    
  848.     def test_aware_datetime_with_microsecond(self):
    
  849.         dt = datetime.datetime(2011, 9, 1, 17, 20, 30, 405060, tzinfo=ICT)
    
  850. 
    
  851.         data = serializers.serialize("python", [Event(dt=dt)])
    
  852.         self.assert_python_contains_datetime(data, dt)
    
  853.         obj = next(serializers.deserialize("python", data)).object
    
  854.         self.assertEqual(obj.dt, dt)
    
  855. 
    
  856.         data = serializers.serialize("json", [Event(dt=dt)])
    
  857.         self.assert_json_contains_datetime(data, "2011-09-01T17:20:30.405+07:00")
    
  858.         obj = next(serializers.deserialize("json", data)).object
    
  859.         self.assertEqual(obj.dt, dt.replace(microsecond=405000))
    
  860. 
    
  861.         data = serializers.serialize("xml", [Event(dt=dt)])
    
  862.         self.assert_xml_contains_datetime(data, "2011-09-01T17:20:30.405060+07:00")
    
  863.         obj = next(serializers.deserialize("xml", data)).object
    
  864.         self.assertEqual(obj.dt, dt)
    
  865. 
    
  866.         if not isinstance(
    
  867.             serializers.get_serializer("yaml"), serializers.BadSerializer
    
  868.         ):
    
  869.             data = serializers.serialize(
    
  870.                 "yaml", [Event(dt=dt)], default_flow_style=None
    
  871.             )
    
  872.             self.assert_yaml_contains_datetime(data, "2011-09-01 17:20:30.405060+07:00")
    
  873.             obj = next(serializers.deserialize("yaml", data)).object
    
  874.             if HAS_YAML and yaml.__version__ < "5.3":
    
  875.                 self.assertEqual(obj.dt.replace(tzinfo=UTC), dt)
    
  876.             else:
    
  877.                 self.assertEqual(obj.dt, dt)
    
  878. 
    
  879.     def test_aware_datetime_in_utc(self):
    
  880.         dt = datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
    
  881. 
    
  882.         data = serializers.serialize("python", [Event(dt=dt)])
    
  883.         self.assert_python_contains_datetime(data, dt)
    
  884.         obj = next(serializers.deserialize("python", data)).object
    
  885.         self.assertEqual(obj.dt, dt)
    
  886. 
    
  887.         data = serializers.serialize("json", [Event(dt=dt)])
    
  888.         self.assert_json_contains_datetime(data, "2011-09-01T10:20:30Z")
    
  889.         obj = next(serializers.deserialize("json", data)).object
    
  890.         self.assertEqual(obj.dt, dt)
    
  891. 
    
  892.         data = serializers.serialize("xml", [Event(dt=dt)])
    
  893.         self.assert_xml_contains_datetime(data, "2011-09-01T10:20:30+00:00")
    
  894.         obj = next(serializers.deserialize("xml", data)).object
    
  895.         self.assertEqual(obj.dt, dt)
    
  896. 
    
  897.         if not isinstance(
    
  898.             serializers.get_serializer("yaml"), serializers.BadSerializer
    
  899.         ):
    
  900.             data = serializers.serialize(
    
  901.                 "yaml", [Event(dt=dt)], default_flow_style=None
    
  902.             )
    
  903.             self.assert_yaml_contains_datetime(data, "2011-09-01 10:20:30+00:00")
    
  904.             obj = next(serializers.deserialize("yaml", data)).object
    
  905.             self.assertEqual(obj.dt.replace(tzinfo=UTC), dt)
    
  906. 
    
  907.     def test_aware_datetime_in_local_timezone(self):
    
  908.         dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
    
  909. 
    
  910.         data = serializers.serialize("python", [Event(dt=dt)])
    
  911.         self.assert_python_contains_datetime(data, dt)
    
  912.         obj = next(serializers.deserialize("python", data)).object
    
  913.         self.assertEqual(obj.dt, dt)
    
  914. 
    
  915.         data = serializers.serialize("json", [Event(dt=dt)])
    
  916.         self.assert_json_contains_datetime(data, "2011-09-01T13:20:30+03:00")
    
  917.         obj = next(serializers.deserialize("json", data)).object
    
  918.         self.assertEqual(obj.dt, dt)
    
  919. 
    
  920.         data = serializers.serialize("xml", [Event(dt=dt)])
    
  921.         self.assert_xml_contains_datetime(data, "2011-09-01T13:20:30+03:00")
    
  922.         obj = next(serializers.deserialize("xml", data)).object
    
  923.         self.assertEqual(obj.dt, dt)
    
  924. 
    
  925.         if not isinstance(
    
  926.             serializers.get_serializer("yaml"), serializers.BadSerializer
    
  927.         ):
    
  928.             data = serializers.serialize(
    
  929.                 "yaml", [Event(dt=dt)], default_flow_style=None
    
  930.             )
    
  931.             self.assert_yaml_contains_datetime(data, "2011-09-01 13:20:30+03:00")
    
  932.             obj = next(serializers.deserialize("yaml", data)).object
    
  933.             if HAS_YAML and yaml.__version__ < "5.3":
    
  934.                 self.assertEqual(obj.dt.replace(tzinfo=UTC), dt)
    
  935.             else:
    
  936.                 self.assertEqual(obj.dt, dt)
    
  937. 
    
  938.     def test_aware_datetime_in_other_timezone(self):
    
  939.         dt = datetime.datetime(2011, 9, 1, 17, 20, 30, tzinfo=ICT)
    
  940. 
    
  941.         data = serializers.serialize("python", [Event(dt=dt)])
    
  942.         self.assert_python_contains_datetime(data, dt)
    
  943.         obj = next(serializers.deserialize("python", data)).object
    
  944.         self.assertEqual(obj.dt, dt)
    
  945. 
    
  946.         data = serializers.serialize("json", [Event(dt=dt)])
    
  947.         self.assert_json_contains_datetime(data, "2011-09-01T17:20:30+07:00")
    
  948.         obj = next(serializers.deserialize("json", data)).object
    
  949.         self.assertEqual(obj.dt, dt)
    
  950. 
    
  951.         data = serializers.serialize("xml", [Event(dt=dt)])
    
  952.         self.assert_xml_contains_datetime(data, "2011-09-01T17:20:30+07:00")
    
  953.         obj = next(serializers.deserialize("xml", data)).object
    
  954.         self.assertEqual(obj.dt, dt)
    
  955. 
    
  956.         if not isinstance(
    
  957.             serializers.get_serializer("yaml"), serializers.BadSerializer
    
  958.         ):
    
  959.             data = serializers.serialize(
    
  960.                 "yaml", [Event(dt=dt)], default_flow_style=None
    
  961.             )
    
  962.             self.assert_yaml_contains_datetime(data, "2011-09-01 17:20:30+07:00")
    
  963.             obj = next(serializers.deserialize("yaml", data)).object
    
  964.             if HAS_YAML and yaml.__version__ < "5.3":
    
  965.                 self.assertEqual(obj.dt.replace(tzinfo=UTC), dt)
    
  966.             else:
    
  967.                 self.assertEqual(obj.dt, dt)
    
  968. 
    
  969. 
    
  970. # RemovedInDjango50Warning: When the deprecation ends, remove setUpClass() and
    
  971. # USE_L10N=False. The tests should remain because format-related settings will
    
  972. # take precedence over locale-dictated formats.
    
  973. @override_settings(
    
  974.     DATETIME_FORMAT="c", TIME_ZONE="Africa/Nairobi", USE_L10N=False, USE_TZ=True
    
  975. )
    
  976. class TemplateTests(SimpleTestCase):
    
  977.     @classmethod
    
  978.     def setUpClass(cls):
    
  979.         with ignore_warnings(category=RemovedInDjango50Warning):
    
  980.             super().setUpClass()
    
  981. 
    
  982.     @requires_tz_support
    
  983.     def test_localtime_templatetag_and_filters(self):
    
  984.         """
    
  985.         Test the {% localtime %} templatetag and related filters.
    
  986.         """
    
  987.         datetimes = {
    
  988.             "utc": datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC),
    
  989.             "eat": datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT),
    
  990.             "ict": datetime.datetime(2011, 9, 1, 17, 20, 30, tzinfo=ICT),
    
  991.             "naive": datetime.datetime(2011, 9, 1, 13, 20, 30),
    
  992.         }
    
  993.         templates = {
    
  994.             "notag": Template(
    
  995.                 "{% load tz %}"
    
  996.                 "{{ dt }}|{{ dt|localtime }}|{{ dt|utc }}|{{ dt|timezone:ICT }}"
    
  997.             ),
    
  998.             "noarg": Template(
    
  999.                 "{% load tz %}{% localtime %}{{ dt }}|{{ dt|localtime }}|"
    
  1000.                 "{{ dt|utc }}|{{ dt|timezone:ICT }}{% endlocaltime %}"
    
  1001.             ),
    
  1002.             "on": Template(
    
  1003.                 "{% load tz %}{% localtime on %}{{ dt }}|{{ dt|localtime }}|"
    
  1004.                 "{{ dt|utc }}|{{ dt|timezone:ICT }}{% endlocaltime %}"
    
  1005.             ),
    
  1006.             "off": Template(
    
  1007.                 "{% load tz %}{% localtime off %}{{ dt }}|{{ dt|localtime }}|"
    
  1008.                 "{{ dt|utc }}|{{ dt|timezone:ICT }}{% endlocaltime %}"
    
  1009.             ),
    
  1010.         }
    
  1011. 
    
  1012.         # Transform a list of keys in 'datetimes' to the expected template
    
  1013.         # output. This makes the definition of 'results' more readable.
    
  1014.         def t(*result):
    
  1015.             return "|".join(datetimes[key].isoformat() for key in result)
    
  1016. 
    
  1017.         # Results for USE_TZ = True
    
  1018. 
    
  1019.         results = {
    
  1020.             "utc": {
    
  1021.                 "notag": t("eat", "eat", "utc", "ict"),
    
  1022.                 "noarg": t("eat", "eat", "utc", "ict"),
    
  1023.                 "on": t("eat", "eat", "utc", "ict"),
    
  1024.                 "off": t("utc", "eat", "utc", "ict"),
    
  1025.             },
    
  1026.             "eat": {
    
  1027.                 "notag": t("eat", "eat", "utc", "ict"),
    
  1028.                 "noarg": t("eat", "eat", "utc", "ict"),
    
  1029.                 "on": t("eat", "eat", "utc", "ict"),
    
  1030.                 "off": t("eat", "eat", "utc", "ict"),
    
  1031.             },
    
  1032.             "ict": {
    
  1033.                 "notag": t("eat", "eat", "utc", "ict"),
    
  1034.                 "noarg": t("eat", "eat", "utc", "ict"),
    
  1035.                 "on": t("eat", "eat", "utc", "ict"),
    
  1036.                 "off": t("ict", "eat", "utc", "ict"),
    
  1037.             },
    
  1038.             "naive": {
    
  1039.                 "notag": t("naive", "eat", "utc", "ict"),
    
  1040.                 "noarg": t("naive", "eat", "utc", "ict"),
    
  1041.                 "on": t("naive", "eat", "utc", "ict"),
    
  1042.                 "off": t("naive", "eat", "utc", "ict"),
    
  1043.             },
    
  1044.         }
    
  1045. 
    
  1046.         for k1, dt in datetimes.items():
    
  1047.             for k2, tpl in templates.items():
    
  1048.                 ctx = Context({"dt": dt, "ICT": ICT})
    
  1049.                 actual = tpl.render(ctx)
    
  1050.                 expected = results[k1][k2]
    
  1051.                 self.assertEqual(
    
  1052.                     actual, expected, "%s / %s: %r != %r" % (k1, k2, actual, expected)
    
  1053.                 )
    
  1054. 
    
  1055.         # Changes for USE_TZ = False
    
  1056. 
    
  1057.         results["utc"]["notag"] = t("utc", "eat", "utc", "ict")
    
  1058.         results["ict"]["notag"] = t("ict", "eat", "utc", "ict")
    
  1059. 
    
  1060.         with self.settings(USE_TZ=False):
    
  1061.             for k1, dt in datetimes.items():
    
  1062.                 for k2, tpl in templates.items():
    
  1063.                     ctx = Context({"dt": dt, "ICT": ICT})
    
  1064.                     actual = tpl.render(ctx)
    
  1065.                     expected = results[k1][k2]
    
  1066.                     self.assertEqual(
    
  1067.                         actual,
    
  1068.                         expected,
    
  1069.                         "%s / %s: %r != %r" % (k1, k2, actual, expected),
    
  1070.                     )
    
  1071. 
    
  1072.     def test_localtime_filters_with_iana(self):
    
  1073.         """
    
  1074.         Test the |localtime, |utc, and |timezone filters with iana zones.
    
  1075.         """
    
  1076.         # Use an IANA timezone as local time
    
  1077.         tpl = Template("{% load tz %}{{ dt|localtime }}|{{ dt|utc }}")
    
  1078.         ctx = Context({"dt": datetime.datetime(2011, 9, 1, 12, 20, 30)})
    
  1079. 
    
  1080.         with self.settings(TIME_ZONE="Europe/Paris"):
    
  1081.             self.assertEqual(
    
  1082.                 tpl.render(ctx), "2011-09-01T12:20:30+02:00|2011-09-01T10:20:30+00:00"
    
  1083.             )
    
  1084. 
    
  1085.         # Use an IANA timezone as argument
    
  1086.         for tz in get_timezones("Europe/Paris"):
    
  1087.             with self.subTest(repr(tz)):
    
  1088.                 tpl = Template("{% load tz %}{{ dt|timezone:tz }}")
    
  1089.                 ctx = Context(
    
  1090.                     {
    
  1091.                         "dt": datetime.datetime(2011, 9, 1, 13, 20, 30),
    
  1092.                         "tz": tz,
    
  1093.                     }
    
  1094.                 )
    
  1095.                 self.assertEqual(tpl.render(ctx), "2011-09-01T12:20:30+02:00")
    
  1096. 
    
  1097.     def test_localtime_templatetag_invalid_argument(self):
    
  1098.         with self.assertRaises(TemplateSyntaxError):
    
  1099.             Template("{% load tz %}{% localtime foo %}{% endlocaltime %}").render()
    
  1100. 
    
  1101.     def test_localtime_filters_do_not_raise_exceptions(self):
    
  1102.         """
    
  1103.         Test the |localtime, |utc, and |timezone filters on bad inputs.
    
  1104.         """
    
  1105.         tpl = Template(
    
  1106.             "{% load tz %}{{ dt }}|{{ dt|localtime }}|{{ dt|utc }}|{{ dt|timezone:tz }}"
    
  1107.         )
    
  1108.         with self.settings(USE_TZ=True):
    
  1109.             # bad datetime value
    
  1110.             ctx = Context({"dt": None, "tz": ICT})
    
  1111.             self.assertEqual(tpl.render(ctx), "None|||")
    
  1112.             ctx = Context({"dt": "not a date", "tz": ICT})
    
  1113.             self.assertEqual(tpl.render(ctx), "not a date|||")
    
  1114.             # bad timezone value
    
  1115.             tpl = Template("{% load tz %}{{ dt|timezone:tz }}")
    
  1116.             ctx = Context({"dt": datetime.datetime(2011, 9, 1, 13, 20, 30), "tz": None})
    
  1117.             self.assertEqual(tpl.render(ctx), "")
    
  1118.             ctx = Context(
    
  1119.                 {"dt": datetime.datetime(2011, 9, 1, 13, 20, 30), "tz": "not a tz"}
    
  1120.             )
    
  1121.             self.assertEqual(tpl.render(ctx), "")
    
  1122. 
    
  1123.     @requires_tz_support
    
  1124.     def test_timezone_templatetag(self):
    
  1125.         """
    
  1126.         Test the {% timezone %} templatetag.
    
  1127.         """
    
  1128.         tpl = Template(
    
  1129.             "{% load tz %}"
    
  1130.             "{{ dt }}|"
    
  1131.             "{% timezone tz1 %}"
    
  1132.             "{{ dt }}|"
    
  1133.             "{% timezone tz2 %}"
    
  1134.             "{{ dt }}"
    
  1135.             "{% endtimezone %}"
    
  1136.             "{% endtimezone %}"
    
  1137.         )
    
  1138.         ctx = Context(
    
  1139.             {
    
  1140.                 "dt": datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC),
    
  1141.                 "tz1": ICT,
    
  1142.                 "tz2": None,
    
  1143.             }
    
  1144.         )
    
  1145.         self.assertEqual(
    
  1146.             tpl.render(ctx),
    
  1147.             "2011-09-01T13:20:30+03:00|2011-09-01T17:20:30+07:00|"
    
  1148.             "2011-09-01T13:20:30+03:00",
    
  1149.         )
    
  1150. 
    
  1151.     def test_timezone_templatetag_with_iana(self):
    
  1152.         """
    
  1153.         Test the {% timezone %} templatetag with IANA time zone providers.
    
  1154.         """
    
  1155.         tpl = Template("{% load tz %}{% timezone tz %}{{ dt }}{% endtimezone %}")
    
  1156. 
    
  1157.         # Use a IANA timezone as argument
    
  1158.         for tz in get_timezones("Europe/Paris"):
    
  1159.             with self.subTest(repr(tz)):
    
  1160.                 ctx = Context(
    
  1161.                     {
    
  1162.                         "dt": datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT),
    
  1163.                         "tz": tz,
    
  1164.                     }
    
  1165.                 )
    
  1166.                 self.assertEqual(tpl.render(ctx), "2011-09-01T12:20:30+02:00")
    
  1167. 
    
  1168.         # Use a IANA timezone name as argument
    
  1169.         ctx = Context(
    
  1170.             {
    
  1171.                 "dt": datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT),
    
  1172.                 "tz": "Europe/Paris",
    
  1173.             }
    
  1174.         )
    
  1175.         self.assertEqual(tpl.render(ctx), "2011-09-01T12:20:30+02:00")
    
  1176. 
    
  1177.     @ignore_warnings(category=RemovedInDjango50Warning)
    
  1178.     def test_timezone_templatetag_invalid_argument(self):
    
  1179.         with self.assertRaises(TemplateSyntaxError):
    
  1180.             Template("{% load tz %}{% timezone %}{% endtimezone %}").render()
    
  1181.         with self.assertRaises(zoneinfo.ZoneInfoNotFoundError):
    
  1182.             Template("{% load tz %}{% timezone tz %}{% endtimezone %}").render(
    
  1183.                 Context({"tz": "foobar"})
    
  1184.             )
    
  1185.         if pytz is not None:
    
  1186.             with override_settings(USE_DEPRECATED_PYTZ=True), self.assertRaises(
    
  1187.                 pytz.UnknownTimeZoneError
    
  1188.             ):
    
  1189.                 Template("{% load tz %}{% timezone tz %}{% endtimezone %}").render(
    
  1190.                     Context({"tz": "foobar"})
    
  1191.                 )
    
  1192. 
    
  1193.     @skipIf(sys.platform == "win32", "Windows uses non-standard time zone names")
    
  1194.     def test_get_current_timezone_templatetag(self):
    
  1195.         """
    
  1196.         Test the {% get_current_timezone %} templatetag.
    
  1197.         """
    
  1198.         tpl = Template(
    
  1199.             "{% load tz %}{% get_current_timezone as time_zone %}{{ time_zone }}"
    
  1200.         )
    
  1201. 
    
  1202.         self.assertEqual(tpl.render(Context()), "Africa/Nairobi")
    
  1203.         with timezone.override(UTC):
    
  1204.             self.assertEqual(tpl.render(Context()), "UTC")
    
  1205. 
    
  1206.         tpl = Template(
    
  1207.             "{% load tz %}{% timezone tz %}{% get_current_timezone as time_zone %}"
    
  1208.             "{% endtimezone %}{{ time_zone }}"
    
  1209.         )
    
  1210. 
    
  1211.         self.assertEqual(tpl.render(Context({"tz": ICT})), "+0700")
    
  1212.         with timezone.override(UTC):
    
  1213.             self.assertEqual(tpl.render(Context({"tz": ICT})), "+0700")
    
  1214. 
    
  1215.     def test_get_current_timezone_templatetag_with_iana(self):
    
  1216.         """
    
  1217.         Test the {% get_current_timezone %} templatetag with pytz.
    
  1218.         """
    
  1219.         tpl = Template(
    
  1220.             "{% load tz %}{% get_current_timezone as time_zone %}{{ time_zone }}"
    
  1221.         )
    
  1222.         for tz in get_timezones("Europe/Paris"):
    
  1223.             with self.subTest(repr(tz)):
    
  1224.                 with timezone.override(tz):
    
  1225.                     self.assertEqual(tpl.render(Context()), "Europe/Paris")
    
  1226. 
    
  1227.         tpl = Template(
    
  1228.             "{% load tz %}{% timezone 'Europe/Paris' %}"
    
  1229.             "{% get_current_timezone as time_zone %}{% endtimezone %}"
    
  1230.             "{{ time_zone }}"
    
  1231.         )
    
  1232.         self.assertEqual(tpl.render(Context()), "Europe/Paris")
    
  1233. 
    
  1234.     def test_get_current_timezone_templatetag_invalid_argument(self):
    
  1235.         msg = (
    
  1236.             "'get_current_timezone' requires 'as variable' (got "
    
  1237.             "['get_current_timezone'])"
    
  1238.         )
    
  1239.         with self.assertRaisesMessage(TemplateSyntaxError, msg):
    
  1240.             Template("{% load tz %}{% get_current_timezone %}").render()
    
  1241. 
    
  1242.     @skipIf(sys.platform == "win32", "Windows uses non-standard time zone names")
    
  1243.     def test_tz_template_context_processor(self):
    
  1244.         """
    
  1245.         Test the django.template.context_processors.tz template context processor.
    
  1246.         """
    
  1247.         tpl = Template("{{ TIME_ZONE }}")
    
  1248.         context = Context()
    
  1249.         self.assertEqual(tpl.render(context), "")
    
  1250.         request_context = RequestContext(
    
  1251.             HttpRequest(), processors=[context_processors.tz]
    
  1252.         )
    
  1253.         self.assertEqual(tpl.render(request_context), "Africa/Nairobi")
    
  1254. 
    
  1255.     @requires_tz_support
    
  1256.     def test_date_and_time_template_filters(self):
    
  1257.         tpl = Template("{{ dt|date:'Y-m-d' }} at {{ dt|time:'H:i:s' }}")
    
  1258.         ctx = Context({"dt": datetime.datetime(2011, 9, 1, 20, 20, 20, tzinfo=UTC)})
    
  1259.         self.assertEqual(tpl.render(ctx), "2011-09-01 at 23:20:20")
    
  1260.         with timezone.override(ICT):
    
  1261.             self.assertEqual(tpl.render(ctx), "2011-09-02 at 03:20:20")
    
  1262. 
    
  1263.     def test_date_and_time_template_filters_honor_localtime(self):
    
  1264.         tpl = Template(
    
  1265.             "{% load tz %}{% localtime off %}{{ dt|date:'Y-m-d' }} at "
    
  1266.             "{{ dt|time:'H:i:s' }}{% endlocaltime %}"
    
  1267.         )
    
  1268.         ctx = Context({"dt": datetime.datetime(2011, 9, 1, 20, 20, 20, tzinfo=UTC)})
    
  1269.         self.assertEqual(tpl.render(ctx), "2011-09-01 at 20:20:20")
    
  1270.         with timezone.override(ICT):
    
  1271.             self.assertEqual(tpl.render(ctx), "2011-09-01 at 20:20:20")
    
  1272. 
    
  1273.     @requires_tz_support
    
  1274.     def test_now_template_tag_uses_current_time_zone(self):
    
  1275.         # Regression for #17343
    
  1276.         tpl = Template('{% now "O" %}')
    
  1277.         self.assertEqual(tpl.render(Context({})), "+0300")
    
  1278.         with timezone.override(ICT):
    
  1279.             self.assertEqual(tpl.render(Context({})), "+0700")
    
  1280. 
    
  1281. 
    
  1282. # RemovedInDjango50Warning: When the deprecation ends, remove setUpClass() and
    
  1283. # USE_L10N=False. The tests should remain because format-related settings will
    
  1284. # take precedence over locale-dictated formats.
    
  1285. @override_settings(
    
  1286.     DATETIME_FORMAT="c", TIME_ZONE="Africa/Nairobi", USE_L10N=False, USE_TZ=False
    
  1287. )
    
  1288. class LegacyFormsTests(TestCase):
    
  1289.     @classmethod
    
  1290.     def setUpClass(cls):
    
  1291.         with ignore_warnings(category=RemovedInDjango50Warning):
    
  1292.             super().setUpClass()
    
  1293. 
    
  1294.     def test_form(self):
    
  1295.         form = EventForm({"dt": "2011-09-01 13:20:30"})
    
  1296.         self.assertTrue(form.is_valid())
    
  1297.         self.assertEqual(
    
  1298.             form.cleaned_data["dt"], datetime.datetime(2011, 9, 1, 13, 20, 30)
    
  1299.         )
    
  1300. 
    
  1301.     def test_form_with_non_existent_time(self):
    
  1302.         form = EventForm({"dt": "2011-03-27 02:30:00"})
    
  1303.         for tz in get_timezones("Europe/Paris"):
    
  1304.             with self.subTest(repr(tz)):
    
  1305.                 with timezone.override(tz):
    
  1306.                     # This is a bug.
    
  1307.                     self.assertTrue(form.is_valid())
    
  1308.                     self.assertEqual(
    
  1309.                         form.cleaned_data["dt"],
    
  1310.                         datetime.datetime(2011, 3, 27, 2, 30, 0),
    
  1311.                     )
    
  1312. 
    
  1313.     def test_form_with_ambiguous_time(self):
    
  1314.         form = EventForm({"dt": "2011-10-30 02:30:00"})
    
  1315.         for tz in get_timezones("Europe/Paris"):
    
  1316.             with self.subTest(repr(tz)):
    
  1317.                 with timezone.override(tz):
    
  1318.                     # This is a bug.
    
  1319.                     self.assertTrue(form.is_valid())
    
  1320.                     self.assertEqual(
    
  1321.                         form.cleaned_data["dt"],
    
  1322.                         datetime.datetime(2011, 10, 30, 2, 30, 0),
    
  1323.                     )
    
  1324. 
    
  1325.     def test_split_form(self):
    
  1326.         form = EventSplitForm({"dt_0": "2011-09-01", "dt_1": "13:20:30"})
    
  1327.         self.assertTrue(form.is_valid())
    
  1328.         self.assertEqual(
    
  1329.             form.cleaned_data["dt"], datetime.datetime(2011, 9, 1, 13, 20, 30)
    
  1330.         )
    
  1331. 
    
  1332.     def test_model_form(self):
    
  1333.         EventModelForm({"dt": "2011-09-01 13:20:30"}).save()
    
  1334.         e = Event.objects.get()
    
  1335.         self.assertEqual(e.dt, datetime.datetime(2011, 9, 1, 13, 20, 30))
    
  1336. 
    
  1337. 
    
  1338. # RemovedInDjango50Warning: When the deprecation ends, remove setUpClass() and
    
  1339. # USE_L10N=False. The tests should remain because format-related settings will
    
  1340. # take precedence over locale-dictated formats.
    
  1341. @override_settings(
    
  1342.     DATETIME_FORMAT="c", TIME_ZONE="Africa/Nairobi", USE_L10N=False, USE_TZ=True
    
  1343. )
    
  1344. class NewFormsTests(TestCase):
    
  1345.     @classmethod
    
  1346.     def setUpClass(cls):
    
  1347.         with ignore_warnings(category=RemovedInDjango50Warning):
    
  1348.             super().setUpClass()
    
  1349. 
    
  1350.     @requires_tz_support
    
  1351.     def test_form(self):
    
  1352.         form = EventForm({"dt": "2011-09-01 13:20:30"})
    
  1353.         self.assertTrue(form.is_valid())
    
  1354.         self.assertEqual(
    
  1355.             form.cleaned_data["dt"],
    
  1356.             datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC),
    
  1357.         )
    
  1358. 
    
  1359.     def test_form_with_other_timezone(self):
    
  1360.         form = EventForm({"dt": "2011-09-01 17:20:30"})
    
  1361.         with timezone.override(ICT):
    
  1362.             self.assertTrue(form.is_valid())
    
  1363.             self.assertEqual(
    
  1364.                 form.cleaned_data["dt"],
    
  1365.                 datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC),
    
  1366.             )
    
  1367. 
    
  1368.     def test_form_with_non_existent_time(self):
    
  1369.         for tz in get_timezones("Europe/Paris"):
    
  1370.             with self.subTest(repr(tz)):
    
  1371.                 with timezone.override(tz):
    
  1372.                     form = EventForm({"dt": "2011-03-27 02:30:00"})
    
  1373.                     self.assertFalse(form.is_valid())
    
  1374.                     self.assertEqual(
    
  1375.                         form.errors["dt"],
    
  1376.                         [
    
  1377.                             "2011-03-27 02:30:00 couldn’t be interpreted in time zone "
    
  1378.                             "Europe/Paris; it may be ambiguous or it may not exist."
    
  1379.                         ],
    
  1380.                     )
    
  1381. 
    
  1382.     def test_form_with_ambiguous_time(self):
    
  1383.         for tz in get_timezones("Europe/Paris"):
    
  1384.             with self.subTest(repr(tz)):
    
  1385.                 with timezone.override(tz):
    
  1386.                     form = EventForm({"dt": "2011-10-30 02:30:00"})
    
  1387.                     self.assertFalse(form.is_valid())
    
  1388.                     self.assertEqual(
    
  1389.                         form.errors["dt"],
    
  1390.                         [
    
  1391.                             "2011-10-30 02:30:00 couldn’t be interpreted in time zone "
    
  1392.                             "Europe/Paris; it may be ambiguous or it may not exist."
    
  1393.                         ],
    
  1394.                     )
    
  1395. 
    
  1396.     @requires_tz_support
    
  1397.     def test_split_form(self):
    
  1398.         form = EventSplitForm({"dt_0": "2011-09-01", "dt_1": "13:20:30"})
    
  1399.         self.assertTrue(form.is_valid())
    
  1400.         self.assertEqual(
    
  1401.             form.cleaned_data["dt"],
    
  1402.             datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC),
    
  1403.         )
    
  1404. 
    
  1405.     @requires_tz_support
    
  1406.     def test_localized_form(self):
    
  1407.         form = EventLocalizedForm(
    
  1408.             initial={"dt": datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)}
    
  1409.         )
    
  1410.         with timezone.override(ICT):
    
  1411.             self.assertIn("2011-09-01 17:20:30", str(form))
    
  1412. 
    
  1413.     @requires_tz_support
    
  1414.     def test_model_form(self):
    
  1415.         EventModelForm({"dt": "2011-09-01 13:20:30"}).save()
    
  1416.         e = Event.objects.get()
    
  1417.         self.assertEqual(e.dt, datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC))
    
  1418. 
    
  1419.     @requires_tz_support
    
  1420.     def test_localized_model_form(self):
    
  1421.         form = EventLocalizedModelForm(
    
  1422.             instance=Event(dt=datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT))
    
  1423.         )
    
  1424.         with timezone.override(ICT):
    
  1425.             self.assertIn("2011-09-01 17:20:30", str(form))
    
  1426. 
    
  1427. 
    
  1428. @override_settings(
    
  1429.     DATETIME_FORMAT="c",
    
  1430.     TIME_ZONE="Africa/Nairobi",
    
  1431.     USE_L10N=False,
    
  1432.     USE_TZ=True,
    
  1433.     ROOT_URLCONF="timezones.urls",
    
  1434. )
    
  1435. class AdminTests(TestCase):
    
  1436.     @classmethod
    
  1437.     def setUpClass(cls):
    
  1438.         with ignore_warnings(category=RemovedInDjango50Warning):
    
  1439.             super().setUpClass()
    
  1440. 
    
  1441.     @classmethod
    
  1442.     def setUpTestData(cls):
    
  1443.         cls.u1 = User.objects.create_user(
    
  1444.             password="secret",
    
  1445.             last_login=datetime.datetime(2007, 5, 30, 13, 20, 10, tzinfo=UTC),
    
  1446.             is_superuser=True,
    
  1447.             username="super",
    
  1448.             first_name="Super",
    
  1449.             last_name="User",
    
  1450.             email="[email protected]",
    
  1451.             is_staff=True,
    
  1452.             is_active=True,
    
  1453.             date_joined=datetime.datetime(2007, 5, 30, 13, 20, 10, tzinfo=UTC),
    
  1454.         )
    
  1455. 
    
  1456.     def setUp(self):
    
  1457.         self.client.force_login(self.u1)
    
  1458. 
    
  1459.     @requires_tz_support
    
  1460.     def test_changelist(self):
    
  1461.         e = Event.objects.create(
    
  1462.             dt=datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
    
  1463.         )
    
  1464.         response = self.client.get(reverse("admin_tz:timezones_event_changelist"))
    
  1465.         self.assertContains(response, e.dt.astimezone(EAT).isoformat())
    
  1466. 
    
  1467.     def test_changelist_in_other_timezone(self):
    
  1468.         e = Event.objects.create(
    
  1469.             dt=datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
    
  1470.         )
    
  1471.         with timezone.override(ICT):
    
  1472.             response = self.client.get(reverse("admin_tz:timezones_event_changelist"))
    
  1473.         self.assertContains(response, e.dt.astimezone(ICT).isoformat())
    
  1474. 
    
  1475.     @requires_tz_support
    
  1476.     def test_change_editable(self):
    
  1477.         e = Event.objects.create(
    
  1478.             dt=datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
    
  1479.         )
    
  1480.         response = self.client.get(
    
  1481.             reverse("admin_tz:timezones_event_change", args=(e.pk,))
    
  1482.         )
    
  1483.         self.assertContains(response, e.dt.astimezone(EAT).date().isoformat())
    
  1484.         self.assertContains(response, e.dt.astimezone(EAT).time().isoformat())
    
  1485. 
    
  1486.     def test_change_editable_in_other_timezone(self):
    
  1487.         e = Event.objects.create(
    
  1488.             dt=datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC)
    
  1489.         )
    
  1490.         with timezone.override(ICT):
    
  1491.             response = self.client.get(
    
  1492.                 reverse("admin_tz:timezones_event_change", args=(e.pk,))
    
  1493.             )
    
  1494.         self.assertContains(response, e.dt.astimezone(ICT).date().isoformat())
    
  1495.         self.assertContains(response, e.dt.astimezone(ICT).time().isoformat())
    
  1496. 
    
  1497.     @requires_tz_support
    
  1498.     def test_change_readonly(self):
    
  1499.         Timestamp.objects.create()
    
  1500.         # re-fetch the object for backends that lose microseconds (MySQL)
    
  1501.         t = Timestamp.objects.get()
    
  1502.         response = self.client.get(
    
  1503.             reverse("admin_tz:timezones_timestamp_change", args=(t.pk,))
    
  1504.         )
    
  1505.         self.assertContains(response, t.created.astimezone(EAT).isoformat())
    
  1506. 
    
  1507.     def test_change_readonly_in_other_timezone(self):
    
  1508.         Timestamp.objects.create()
    
  1509.         # re-fetch the object for backends that lose microseconds (MySQL)
    
  1510.         t = Timestamp.objects.get()
    
  1511.         with timezone.override(ICT):
    
  1512.             response = self.client.get(
    
  1513.                 reverse("admin_tz:timezones_timestamp_change", args=(t.pk,))
    
  1514.             )
    
  1515.         self.assertContains(response, t.created.astimezone(ICT).isoformat())