1. import datetime
    
  2. import unittest
    
  3. 
    
  4. try:
    
  5.     import pytz
    
  6. except ImportError:
    
  7.     pytz = None
    
  8. 
    
  9. from django.test import TestCase, ignore_warnings, override_settings
    
  10. from django.utils import timezone
    
  11. from django.utils.deprecation import RemovedInDjango50Warning
    
  12. 
    
  13. from .models import Article, Category, Comment
    
  14. 
    
  15. 
    
  16. class DateTimesTests(TestCase):
    
  17.     def test_related_model_traverse(self):
    
  18.         a1 = Article.objects.create(
    
  19.             title="First one",
    
  20.             pub_date=datetime.datetime(2005, 7, 28, 9, 0, 0),
    
  21.         )
    
  22.         a2 = Article.objects.create(
    
  23.             title="Another one",
    
  24.             pub_date=datetime.datetime(2010, 7, 28, 10, 0, 0),
    
  25.         )
    
  26.         a3 = Article.objects.create(
    
  27.             title="Third one, in the first day",
    
  28.             pub_date=datetime.datetime(2005, 7, 28, 17, 0, 0),
    
  29.         )
    
  30. 
    
  31.         a1.comments.create(
    
  32.             text="Im the HULK!",
    
  33.             pub_date=datetime.datetime(2005, 7, 28, 9, 30, 0),
    
  34.         )
    
  35.         a1.comments.create(
    
  36.             text="HULK SMASH!",
    
  37.             pub_date=datetime.datetime(2005, 7, 29, 1, 30, 0),
    
  38.         )
    
  39.         a2.comments.create(
    
  40.             text="LMAO",
    
  41.             pub_date=datetime.datetime(2010, 7, 28, 10, 10, 10),
    
  42.         )
    
  43.         a3.comments.create(
    
  44.             text="+1",
    
  45.             pub_date=datetime.datetime(2005, 8, 29, 10, 10, 10),
    
  46.         )
    
  47. 
    
  48.         c = Category.objects.create(name="serious-news")
    
  49.         c.articles.add(a1, a3)
    
  50. 
    
  51.         self.assertSequenceEqual(
    
  52.             Comment.objects.datetimes("article__pub_date", "year"),
    
  53.             [
    
  54.                 datetime.datetime(2005, 1, 1),
    
  55.                 datetime.datetime(2010, 1, 1),
    
  56.             ],
    
  57.         )
    
  58.         self.assertSequenceEqual(
    
  59.             Comment.objects.datetimes("article__pub_date", "month"),
    
  60.             [
    
  61.                 datetime.datetime(2005, 7, 1),
    
  62.                 datetime.datetime(2010, 7, 1),
    
  63.             ],
    
  64.         )
    
  65.         self.assertSequenceEqual(
    
  66.             Comment.objects.datetimes("article__pub_date", "week"),
    
  67.             [
    
  68.                 datetime.datetime(2005, 7, 25),
    
  69.                 datetime.datetime(2010, 7, 26),
    
  70.             ],
    
  71.         )
    
  72.         self.assertSequenceEqual(
    
  73.             Comment.objects.datetimes("article__pub_date", "day"),
    
  74.             [
    
  75.                 datetime.datetime(2005, 7, 28),
    
  76.                 datetime.datetime(2010, 7, 28),
    
  77.             ],
    
  78.         )
    
  79.         self.assertSequenceEqual(
    
  80.             Article.objects.datetimes("comments__pub_date", "day"),
    
  81.             [
    
  82.                 datetime.datetime(2005, 7, 28),
    
  83.                 datetime.datetime(2005, 7, 29),
    
  84.                 datetime.datetime(2005, 8, 29),
    
  85.                 datetime.datetime(2010, 7, 28),
    
  86.             ],
    
  87.         )
    
  88.         self.assertQuerysetEqual(
    
  89.             Article.objects.datetimes("comments__approval_date", "day"), []
    
  90.         )
    
  91.         self.assertSequenceEqual(
    
  92.             Category.objects.datetimes("articles__pub_date", "day"),
    
  93.             [
    
  94.                 datetime.datetime(2005, 7, 28),
    
  95.             ],
    
  96.         )
    
  97. 
    
  98.     @override_settings(USE_TZ=True)
    
  99.     def test_21432(self):
    
  100.         now = timezone.localtime(timezone.now().replace(microsecond=0))
    
  101.         Article.objects.create(title="First one", pub_date=now)
    
  102.         qs = Article.objects.datetimes("pub_date", "second")
    
  103.         self.assertEqual(qs[0], now)
    
  104. 
    
  105.     @unittest.skipUnless(pytz is not None, "Test requires pytz")
    
  106.     @ignore_warnings(category=RemovedInDjango50Warning)
    
  107.     @override_settings(USE_TZ=True, TIME_ZONE="UTC", USE_DEPRECATED_PYTZ=True)
    
  108.     def test_datetimes_ambiguous_and_invalid_times(self):
    
  109.         sao = pytz.timezone("America/Sao_Paulo")
    
  110.         utc = pytz.UTC
    
  111.         article = Article.objects.create(
    
  112.             title="Article 1",
    
  113.             pub_date=utc.localize(datetime.datetime(2016, 2, 21, 1)),
    
  114.         )
    
  115.         Comment.objects.create(
    
  116.             article=article,
    
  117.             pub_date=utc.localize(datetime.datetime(2016, 10, 16, 13)),
    
  118.         )
    
  119.         with timezone.override(sao):
    
  120.             with self.assertRaisesMessage(
    
  121.                 pytz.AmbiguousTimeError, "2016-02-20 23:00:00"
    
  122.             ):
    
  123.                 Article.objects.datetimes("pub_date", "hour").get()
    
  124.             with self.assertRaisesMessage(
    
  125.                 pytz.NonExistentTimeError, "2016-10-16 00:00:00"
    
  126.             ):
    
  127.                 Comment.objects.datetimes("pub_date", "day").get()
    
  128.             self.assertEqual(
    
  129.                 Article.objects.datetimes("pub_date", "hour", is_dst=False).get().dst(),
    
  130.                 datetime.timedelta(0),
    
  131.             )
    
  132.             self.assertEqual(
    
  133.                 Comment.objects.datetimes("pub_date", "day", is_dst=False).get().dst(),
    
  134.                 datetime.timedelta(0),
    
  135.             )
    
  136.             self.assertEqual(
    
  137.                 Article.objects.datetimes("pub_date", "hour", is_dst=True).get().dst(),
    
  138.                 datetime.timedelta(0, 3600),
    
  139.             )
    
  140.             self.assertEqual(
    
  141.                 Comment.objects.datetimes("pub_date", "hour", is_dst=True).get().dst(),
    
  142.                 datetime.timedelta(0, 3600),
    
  143.             )
    
  144. 
    
  145.     def test_datetimes_returns_available_dates_for_given_scope_and_given_field(self):
    
  146.         pub_dates = [
    
  147.             datetime.datetime(2005, 7, 28, 12, 15),
    
  148.             datetime.datetime(2005, 7, 29, 2, 15),
    
  149.             datetime.datetime(2005, 7, 30, 5, 15),
    
  150.             datetime.datetime(2005, 7, 31, 19, 15),
    
  151.         ]
    
  152.         for i, pub_date in enumerate(pub_dates):
    
  153.             Article(pub_date=pub_date, title="title #{}".format(i)).save()
    
  154. 
    
  155.         self.assertSequenceEqual(
    
  156.             Article.objects.datetimes("pub_date", "year"),
    
  157.             [datetime.datetime(2005, 1, 1, 0, 0)],
    
  158.         )
    
  159.         self.assertSequenceEqual(
    
  160.             Article.objects.datetimes("pub_date", "month"),
    
  161.             [datetime.datetime(2005, 7, 1, 0, 0)],
    
  162.         )
    
  163.         self.assertSequenceEqual(
    
  164.             Article.objects.datetimes("pub_date", "week"),
    
  165.             [datetime.datetime(2005, 7, 25, 0, 0)],
    
  166.         )
    
  167.         self.assertSequenceEqual(
    
  168.             Article.objects.datetimes("pub_date", "day"),
    
  169.             [
    
  170.                 datetime.datetime(2005, 7, 28, 0, 0),
    
  171.                 datetime.datetime(2005, 7, 29, 0, 0),
    
  172.                 datetime.datetime(2005, 7, 30, 0, 0),
    
  173.                 datetime.datetime(2005, 7, 31, 0, 0),
    
  174.             ],
    
  175.         )
    
  176.         self.assertSequenceEqual(
    
  177.             Article.objects.datetimes("pub_date", "day", order="ASC"),
    
  178.             [
    
  179.                 datetime.datetime(2005, 7, 28, 0, 0),
    
  180.                 datetime.datetime(2005, 7, 29, 0, 0),
    
  181.                 datetime.datetime(2005, 7, 30, 0, 0),
    
  182.                 datetime.datetime(2005, 7, 31, 0, 0),
    
  183.             ],
    
  184.         )
    
  185.         self.assertSequenceEqual(
    
  186.             Article.objects.datetimes("pub_date", "day", order="DESC"),
    
  187.             [
    
  188.                 datetime.datetime(2005, 7, 31, 0, 0),
    
  189.                 datetime.datetime(2005, 7, 30, 0, 0),
    
  190.                 datetime.datetime(2005, 7, 29, 0, 0),
    
  191.                 datetime.datetime(2005, 7, 28, 0, 0),
    
  192.             ],
    
  193.         )
    
  194. 
    
  195.     def test_datetimes_has_lazy_iterator(self):
    
  196.         pub_dates = [
    
  197.             datetime.datetime(2005, 7, 28, 12, 15),
    
  198.             datetime.datetime(2005, 7, 29, 2, 15),
    
  199.             datetime.datetime(2005, 7, 30, 5, 15),
    
  200.             datetime.datetime(2005, 7, 31, 19, 15),
    
  201.         ]
    
  202.         for i, pub_date in enumerate(pub_dates):
    
  203.             Article(pub_date=pub_date, title="title #{}".format(i)).save()
    
  204.         # Use iterator() with datetimes() to return a generator that lazily
    
  205.         # requests each result one at a time, to save memory.
    
  206.         dates = []
    
  207.         with self.assertNumQueries(0):
    
  208.             article_datetimes_iterator = Article.objects.datetimes(
    
  209.                 "pub_date", "day", order="DESC"
    
  210.             ).iterator()
    
  211. 
    
  212.         with self.assertNumQueries(1):
    
  213.             for article in article_datetimes_iterator:
    
  214.                 dates.append(article)
    
  215.         self.assertEqual(
    
  216.             dates,
    
  217.             [
    
  218.                 datetime.datetime(2005, 7, 31, 0, 0),
    
  219.                 datetime.datetime(2005, 7, 30, 0, 0),
    
  220.                 datetime.datetime(2005, 7, 29, 0, 0),
    
  221.                 datetime.datetime(2005, 7, 28, 0, 0),
    
  222.             ],
    
  223.         )
    
  224. 
    
  225.     def test_datetimes_disallows_date_fields(self):
    
  226.         dt = datetime.datetime(2005, 7, 28, 12, 15)
    
  227.         Article.objects.create(
    
  228.             pub_date=dt,
    
  229.             published_on=dt.date(),
    
  230.             title="Don't put dates into datetime functions!",
    
  231.         )
    
  232.         with self.assertRaisesMessage(
    
  233.             ValueError, "Cannot truncate DateField 'published_on' to DateTimeField"
    
  234.         ):
    
  235.             list(Article.objects.datetimes("published_on", "second"))
    
  236. 
    
  237.     def test_datetimes_fails_when_given_invalid_kind_argument(self):
    
  238.         msg = (
    
  239.             "'kind' must be one of 'year', 'month', 'week', 'day', 'hour', "
    
  240.             "'minute', or 'second'."
    
  241.         )
    
  242.         with self.assertRaisesMessage(ValueError, msg):
    
  243.             Article.objects.datetimes("pub_date", "bad_kind")
    
  244. 
    
  245.     def test_datetimes_fails_when_given_invalid_order_argument(self):
    
  246.         msg = "'order' must be either 'ASC' or 'DESC'."
    
  247.         with self.assertRaisesMessage(ValueError, msg):
    
  248.             Article.objects.datetimes("pub_date", "year", order="bad order")