From 0c458ef048429ee518b3e448f834141d0429e75f Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Tue, 15 Nov 2022 09:55:13 -0400 Subject: [PATCH] fix: make a few datetime manipulations timezone-aware (#4755) * fix: set tz when passing a date to timesince_days filter * fix: fill in tz for a constructed datetime in idindex/index.py * test: simplify double-negatives in test assertions * test: fix I-D expiration test cases to be tz aware * fix: use tz-aware comparisons for in_draft_expire_freeze method * test: fix tz used for timesince_days filter test case --- ietf/doc/expire.py | 4 ++-- ietf/doc/templatetags/ietf_filters.py | 14 ++++++++++++-- ietf/doc/tests_draft.py | 18 +++++++++++++----- ietf/idindex/index.py | 2 +- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/ietf/doc/expire.py b/ietf/doc/expire.py index 9f82e699c..999d5022d 100644 --- a/ietf/doc/expire.py +++ b/ietf/doc/expire.py @@ -73,10 +73,10 @@ def in_draft_expire_freeze(when=None): d = meeting.get_second_cut_off() # for some reason, the old Perl code started at 9 am - second_cut_off = datetime.datetime.combine(d, datetime.time(9, 0)) + second_cut_off = d.replace(hour=9, minute=0, second=0, microsecond=0) d = meeting.get_ietf_monday() - ietf_monday = datetime.datetime.combine(d, datetime.time(0, 0)) + ietf_monday = datetime.datetime.combine(d, datetime.time(0, 0), tzinfo=meeting.tz()) return second_cut_off <= when < ietf_monday diff --git a/ietf/doc/templatetags/ietf_filters.py b/ietf/doc/templatetags/ietf_filters.py index 9c73840b1..0c76eaee2 100644 --- a/ietf/doc/templatetags/ietf_filters.py +++ b/ietf/doc/templatetags/ietf_filters.py @@ -5,6 +5,7 @@ import datetime import re from urllib.parse import urljoin +from zoneinfo import ZoneInfo from django import template from django.conf import settings @@ -316,9 +317,18 @@ def underline(string): @register.filter(name='timesince_days') def timesince_days(date): - """Returns the number of days since 'date' (relative to now)""" + """Returns the number of days since 'date' (relative to now) + + >>> timesince_days(timezone.now() - datetime.timedelta(days=2)) + 2 + + >>> tz = ZoneInfo(settings.TIME_ZONE) + >>> timesince_days(timezone.now().astimezone(tz).date() - datetime.timedelta(days=2)) + 2 + + """ if date.__class__ is not datetime.datetime: - date = datetime.datetime(date.year, date.month, date.day) + date = datetime.datetime(date.year, date.month, date.day, tzinfo=ZoneInfo(settings.TIME_ZONE)) delta = timezone.now() - date return delta.days diff --git a/ietf/doc/tests_draft.py b/ietf/doc/tests_draft.py index dc24cda9b..4d1ebd083 100644 --- a/ietf/doc/tests_draft.py +++ b/ietf/doc/tests_draft.py @@ -644,11 +644,19 @@ class ExpireIDsTests(DraftFileMixin, TestCase): second_cut_off = meeting.get_second_cut_off() ietf_monday = meeting.get_ietf_monday() - self.assertTrue(not in_draft_expire_freeze(datetime.datetime.combine(second_cut_off - datetime.timedelta(days=7), datetime.time(0, 0, 0)))) - self.assertTrue(not in_draft_expire_freeze(datetime.datetime.combine(second_cut_off, datetime.time(0, 0, 0)))) - self.assertTrue(in_draft_expire_freeze(datetime.datetime.combine(second_cut_off + datetime.timedelta(days=7), datetime.time(0, 0, 0)))) - self.assertTrue(in_draft_expire_freeze(datetime.datetime.combine(ietf_monday - datetime.timedelta(days=1), datetime.time(0, 0, 0)))) - self.assertTrue(not in_draft_expire_freeze(datetime.datetime.combine(ietf_monday, datetime.time(0, 0, 0)))) + self.assertFalse(in_draft_expire_freeze((second_cut_off - datetime.timedelta(days=7)).replace(hour=0, minute=0, second=0))) + self.assertFalse(in_draft_expire_freeze(second_cut_off.replace(hour=0, minute=0, second=0))) + self.assertTrue(in_draft_expire_freeze((second_cut_off + datetime.timedelta(days=7)).replace(hour=0, minute=0, second=0))) + self.assertTrue(in_draft_expire_freeze( + datetime.datetime.combine( + ietf_monday - datetime.timedelta(days=1), + datetime.time(0, 0, 0), + tzinfo=datetime.timezone.utc, + ) + )) + self.assertFalse(in_draft_expire_freeze( + datetime.datetime.combine(ietf_monday, datetime.time(0, 0, 0), tzinfo=datetime.timezone.utc) + )) def test_warn_expirable_drafts(self): from ietf.doc.expire import get_soon_to_expire_drafts, send_expire_warning_for_draft diff --git a/ietf/idindex/index.py b/ietf/idindex/index.py index d864905e4..441febdd9 100644 --- a/ietf/idindex/index.py +++ b/ietf/idindex/index.py @@ -270,7 +270,7 @@ def active_drafts_index_by_group(extra_values=()): groups = [g for g in groups_dict.values() if hasattr(g, "active_drafts")] groups.sort(key=lambda g: g.acronym) - fallback_time = datetime.datetime(1950, 1, 1) + fallback_time = datetime.datetime(1950, 1, 1, tzinfo=datetime.timezone.utc) for g in groups: g.active_drafts.sort(key=lambda d: d.get("initial_rev_time", fallback_time))