diff --git a/bin/add-old-drafts-from-archive.py b/bin/add-old-drafts-from-archive.py index e169ecdcf..239ba7837 100755 --- a/bin/add-old-drafts-from-archive.py +++ b/bin/add-old-drafts-from-archive.py @@ -16,6 +16,7 @@ from django.conf import settings from django.core.validators import validate_email, ValidationError from ietf.utils.draft import PlaintextDraft from ietf.submit.utils import update_authors +from ietf.utils.timezone import date_today import debug # pyflakes:ignore @@ -66,9 +67,9 @@ for name in sorted(names): print name, rev, "Can't parse", p,":",e continue if draft.errors and draft.errors.keys()!=['draftname',]: - print "Errors - could not process", name, rev, datetime.datetime.fromtimestamp(p.stat().st_mtime), draft.errors, draft.get_title().encode('utf8') + print "Errors - could not process", name, rev, datetime.datetime.fromtimestamp(p.stat().st_mtime, datetime.timezone.utc), draft.errors, draft.get_title().encode('utf8') else: - time = datetime.datetime.fromtimestamp(p.stat().st_mtime) + time = datetime.datetime.fromtimestamp(p.stat().st_mtime, datetime.timezone.utc) if not doc: doc = Document.objects.create(name=name, time=time, @@ -140,7 +141,7 @@ for name in sorted(names): doc = doc, rev = rev, by = system, - desc = "Revision added from id-archive on %s by %s"%(datetime.date.today(),sys.argv[0]), + desc = "Revision added from id-archive on %s by %s"%(date_today(),sys.argv[0]), time=time, ) events.append(e) diff --git a/bin/check-copyright b/bin/check-copyright index 6698e3fda..13cbcd858 100755 --- a/bin/check-copyright +++ b/bin/check-copyright @@ -162,7 +162,7 @@ def get_first_commit(path): else: pass except OSError: - rev, who, when = None, None, datetime.datetime.now() + rev, who, when = None, None, datetime.datetime.now(datetime.timezone.utc) return { path: { 'rev': rev, 'who': who, 'date': when.strftime('%Y-%m-%d %H:%M:%S'), }, } diff --git a/ietf/bin/rfc-editor-index-updates b/ietf/bin/rfc-editor-index-updates index 4ff3bf373..dc7abe26b 100755 --- a/ietf/bin/rfc-editor-index-updates +++ b/ietf/bin/rfc-editor-index-updates @@ -29,6 +29,7 @@ from django.core.mail import mail_admins from ietf.doc.utils import rebuild_reference_relations from ietf.utils.log import log from ietf.utils.pipe import pipe +from ietf.utils.timezone import date_today import ietf.sync.rfceditor @@ -39,7 +40,7 @@ parser.add_option("-d", dest="skip_date", options, args = parser.parse_args() -skip_date = datetime.date.today() - datetime.timedelta(days=365) +skip_date = date_today() - datetime.timedelta(days=365) if options.skip_date: skip_date = datetime.datetime.strptime(options.skip_date, "%Y-%m-%d").date() diff --git a/ietf/bin/send-review-reminders b/ietf/bin/send-review-reminders index e74694c8a..317db4376 100755 --- a/ietf/bin/send-review-reminders +++ b/ietf/bin/send-review-reminders @@ -26,8 +26,9 @@ from ietf.review.utils import ( send_unavailability_period_ending_reminder, send_reminder_all_open_reviews, send_review_reminder_overdue_assignment, send_reminder_unconfirmed_assignments) from ietf.utils.log import log +from ietf.utils.timezone import date_today, DEADLINE_TZINFO -today = datetime.date.today() +today = date_today(DEADLINE_TZINFO) for assignment in review_assignments_needing_reviewer_reminder(today): email_reviewer_reminder(assignment) diff --git a/ietf/doc/expire.py b/ietf/doc/expire.py index a2a4a714f..af48827cf 100644 --- a/ietf/doc/expire.py +++ b/ietf/doc/expire.py @@ -18,7 +18,7 @@ from ietf.person.models import Person from ietf.meeting.models import Meeting from ietf.doc.utils import add_state_change_event, update_action_holders from ietf.mailtrigger.utils import gather_address_lists -from ietf.utils.timezone import datetime_today, DEADLINE_TZINFO +from ietf.utils.timezone import date_today, datetime_today, DEADLINE_TZINFO nonexpirable_states: Optional[List[State]] = None @@ -173,7 +173,7 @@ def expire_draft(doc): def clean_up_draft_files(): """Move unidentified and old files out of the Internet Draft directory.""" - cut_off = datetime.date.today() + cut_off = date_today() pattern = os.path.join(settings.INTERNET_DRAFT_PATH, "draft-*.*") filename_re = re.compile(r'^(.*)-(\d\d)$') diff --git a/ietf/doc/factories.py b/ietf/doc/factories.py index 568e79cc7..40e0f506b 100644 --- a/ietf/doc/factories.py +++ b/ietf/doc/factories.py @@ -19,6 +19,7 @@ from ietf.group.models import Group from ietf.person.factories import PersonFactory from ietf.group.factories import RoleFactory from ietf.utils.text import xslugify +from ietf.utils.timezone import date_today def draft_name_generator(type_id,group,n): @@ -321,7 +322,7 @@ class ConflictReviewFactory(BaseDocumentFactory): # This is very skeletal. It is enough for the tests that use it now, but when it's needed, it will need to be improved with, at least, a group generator that backs the object with a review team. class ReviewFactory(BaseDocumentFactory): type_id = 'review' - name = factory.LazyAttribute(lambda o: 'review-doesnotexist-00-%s-%s'%(o.group.acronym,datetime.date.today().isoformat())) + name = factory.LazyAttribute(lambda o: 'review-doesnotexist-00-%s-%s'%(o.group.acronym,date_today().isoformat())) group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='review') class DocAliasFactory(factory.django.DjangoModelFactory): diff --git a/ietf/doc/forms.py b/ietf/doc/forms.py index d209eb0a2..372c43ab0 100644 --- a/ietf/doc/forms.py +++ b/ietf/doc/forms.py @@ -15,6 +15,7 @@ from ietf.person.fields import SearchablePersonField, SearchablePersonsField from ietf.person.models import Email, Person from ietf.name.models import ExtResourceName +from ietf.utils.timezone import date_today from ietf.utils.validators import validate_external_resource_value class TelechatForm(forms.Form): @@ -34,7 +35,7 @@ class TelechatForm(forms.Form): for d in dates: self.page_count[d] = telechat_page_count(date=d).for_approval choice_display[d] = '%s (%s pages)' % (d.strftime("%Y-%m-%d"),self.page_count[d]) - if d-datetime.date.today() < datetime.timedelta(days=13): + if d - date_today() < datetime.timedelta(days=13): choice_display[d] += ' : WARNING - this may not leave enough time for directorate reviews!' self.fields['telechat_date'].choices = [("", "(not on agenda)")] + [(d, choice_display[d]) for d in dates] diff --git a/ietf/doc/lastcall.py b/ietf/doc/lastcall.py index fab3001b1..1c490c64c 100644 --- a/ietf/doc/lastcall.py +++ b/ietf/doc/lastcall.py @@ -1,7 +1,5 @@ # helpers for handling last calls on Internet Drafts -import datetime - from django.db.models import Q from ietf.doc.models import Document, State, DocEvent, LastCallDocEvent, WriteupDocEvent @@ -10,6 +8,8 @@ from ietf.person.models import Person from ietf.doc.utils import add_state_change_event, update_action_holders from ietf.doc.mails import generate_ballot_writeup, generate_approval_mail, generate_last_call_announcement from ietf.doc.mails import send_last_call_request, email_last_call_expired, email_last_call_expired_with_downref +from ietf.utils.timezone import date_today, DEADLINE_TZINFO + def request_last_call(request, doc): if not doc.latest_event(type="changed_ballot_writeup_text"): @@ -33,7 +33,7 @@ def request_last_call(request, doc): e.save() def get_expired_last_calls(): - today = datetime.date.today() + today = date_today(DEADLINE_TZINFO) for d in Document.objects.filter(Q(states__type="draft-iesg", states__slug="lc") | Q(states__type="statchg", states__slug="in-lc")): e = d.latest_event(LastCallDocEvent, type="sent_last_call") diff --git a/ietf/doc/mails.py b/ietf/doc/mails.py index ddc669ed8..54e0f47e2 100644 --- a/ietf/doc/mails.py +++ b/ietf/doc/mails.py @@ -25,6 +25,7 @@ from ietf.doc.utils_bofreq import bofreq_editors, bofreq_responsible from ietf.group.models import Role from ietf.doc.models import Document from ietf.mailtrigger.utils import gather_address_lists +from ietf.utils.timezone import date_today, DEADLINE_TZINFO def email_state_changed(request, doc, text, mailtrigger_id=None): @@ -192,7 +193,7 @@ def generate_ballot_rfceditornote(request, doc): return e def generate_last_call_announcement(request, doc): - expiration_date = datetime.date.today() + datetime.timedelta(days=14) + expiration_date = date_today(DEADLINE_TZINFO) + datetime.timedelta(days=14) if doc.group.type_id in ("individ", "area"): group = "an individual submitter" expiration_date += datetime.timedelta(days=14) diff --git a/ietf/doc/models.py b/ietf/doc/models.py index 3f6a38b5a..c6e06fecd 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -36,7 +36,7 @@ from ietf.utils.decorators import memoize from ietf.utils.validators import validate_no_control_chars from ietf.utils.mail import formataddr from ietf.utils.models import ForeignKey -from ietf.utils.timezone import RPC_TZINFO +from ietf.utils.timezone import date_today, RPC_TZINFO if TYPE_CHECKING: # importing other than for type checking causes errors due to cyclic imports from ietf.meeting.models import ProceedingsMaterial, Session @@ -831,16 +831,20 @@ class Document(DocumentInfo): def telechat_date(self, e=None): if not e: e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat") - return e.telechat_date if e and e.telechat_date and e.telechat_date >= datetime.date.today() else None + return e.telechat_date if e and e.telechat_date and e.telechat_date >= date_today(settings.TIME_ZONE) else None def past_telechat_date(self): "Return the latest telechat date if it isn't in the future; else None" e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat") - return e.telechat_date if e and e.telechat_date and e.telechat_date < datetime.date.today() else None + return e.telechat_date if e and e.telechat_date and e.telechat_date < date_today(settings.TIME_ZONE) else None def previous_telechat_date(self): "Return the most recent telechat date in the past, if any (even if there's another in the future)" - e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat", telechat_date__lt=timezone.now()) + e = self.latest_event( + TelechatDocEvent, + type="scheduled_for_telechat", + telechat_date__lt=date_today(settings.TIME_ZONE), + ) return e.telechat_date if e else None def request_closed_time(self, review_req): @@ -906,14 +910,21 @@ class Document(DocumentInfo): def future_presentations(self): """ returns related SessionPresentation objects for meetings that have not yet ended. This implementation allows for 2 week meetings """ - candidate_presentations = self.sessionpresentation_set.filter(session__meeting__date__gte=datetime.date.today()-datetime.timedelta(days=15)) - return sorted([pres for pres in candidate_presentations if pres.session.meeting.end_date()>=datetime.date.today()], key=lambda x:x.session.meeting.date) + candidate_presentations = self.sessionpresentation_set.filter( + session__meeting__date__gte=date_today() - datetime.timedelta(days=15) + ) + return sorted( + [pres for pres in candidate_presentations + if pres.session.meeting.end_date() >= date_today()], + key=lambda x:x.session.meeting.date, + ) def last_presented(self): """ returns related SessionPresentation objects for the most recent meeting in the past""" # Assumes no two meetings have the same start date - if the assumption is violated, one will be chosen arbitrariy - candidate_presentations = self.sessionpresentation_set.filter(session__meeting__date__lte=datetime.date.today()) - candidate_meetings = set([p.session.meeting for p in candidate_presentations if p.session.meeting.end_date()<datetime.date.today()]) + today = date_today() + candidate_presentations = self.sessionpresentation_set.filter(session__meeting__date__lte=today) + candidate_meetings = set([p.session.meeting for p in candidate_presentations if p.session.meeting.end_date()<today]) if candidate_meetings: mtg = sorted(list(candidate_meetings),key=lambda x:x.date,reverse=True)[0] return self.sessionpresentation_set.filter(session__meeting=mtg) @@ -962,7 +973,7 @@ class Document(DocumentInfo): elif rev_events.exists(): time = rev_events.first().time else: - time = datetime.datetime.fromtimestamp(0) + time = datetime.datetime.fromtimestamp(0, datetime.timezone.utc) dh = DocHistory(name=self.name, rev=rev, doc=self, time=time, type=self.type, title=self.title, stream=self.stream, group=self.group) diff --git a/ietf/doc/templatetags/ballot_icon.py b/ietf/doc/templatetags/ballot_icon.py index ee6be139c..8f9aa9ce8 100644 --- a/ietf/doc/templatetags/ballot_icon.py +++ b/ietf/doc/templatetags/ballot_icon.py @@ -38,6 +38,7 @@ import debug # pyflakes:ignore from django import template from django.urls import reverse as urlreverse from django.db.models import Q +from django.utils import timezone from django.utils.safestring import mark_safe from ietf.ietfauth.utils import user_is_person, has_role @@ -173,17 +174,17 @@ def state_age_colored(doc): if iesg_state in ["dead", "watching", "pub", "idexists"]: return "" try: - state_date = ( + state_datetime = ( doc.docevent_set.filter( Q(type="started_iesg_process") | Q(type="changed_state", statedocevent__state_type="draft-iesg") ) .order_by("-time")[0] - .time.date() + .time ) except IndexError: - state_date = datetime.date(1990, 1, 1) - days = (datetime.date.today() - state_date).days + state_datetime = datetime.datetime(1990, 1, 1, tzinfo=datetime.timezone.utc) + days = (timezone.now() - state_datetime).days # loosely based on # https://trac.ietf.org/trac/iesg/wiki/PublishPath if iesg_state == "lc": diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py index 4bd5b4a2b..19e3669fb 100644 --- a/ietf/doc/tests.py +++ b/ietf/doc/tests.py @@ -58,7 +58,7 @@ from ietf.utils.mail import outbox, empty_outbox from ietf.utils.test_utils import login_testing_unauthorized, unicontent, reload_db_objects from ietf.utils.test_utils import TestCase from ietf.utils.text import normalize_text -from ietf.utils.timezone import datetime_today, DEADLINE_TZINFO, RPC_TZINFO +from ietf.utils.timezone import date_today, datetime_today, DEADLINE_TZINFO, RPC_TZINFO class SearchTests(TestCase): @@ -2232,7 +2232,7 @@ class DocumentMeetingTests(TestCase): self.other_chair = PersonFactory() self.other_group.role_set.create(name_id='chair',person=self.other_chair,email=self.other_chair.email()) - today = datetime.date.today() + today = date_today() cut_days = settings.MEETING_MATERIALS_DEFAULT_SUBMISSION_CORRECTION_DAYS self.past_cutoff = SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=1+cut_days)) self.past = SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=cut_days/2)) diff --git a/ietf/doc/tests_ballot.py b/ietf/doc/tests_ballot.py index 163a98a46..8b8d1c1b1 100644 --- a/ietf/doc/tests_ballot.py +++ b/ietf/doc/tests_ballot.py @@ -31,6 +31,7 @@ from ietf.person.utils import get_active_ads from ietf.utils.test_utils import TestCase, login_testing_unauthorized from ietf.utils.mail import outbox, empty_outbox, get_payload_text from ietf.utils.text import unwrap +from ietf.utils.timezone import date_today class EditPositionTests(TestCase): @@ -899,7 +900,7 @@ class MakeLastCallTests(TestCase): mailbox_before = len(outbox) - last_call_sent_date = datetime.date.today() + last_call_sent_date = date_today() expire_date = last_call_sent_date+datetime.timedelta(days=14) r = self.client.post(url, diff --git a/ietf/doc/tests_draft.py b/ietf/doc/tests_draft.py index a4cb02f11..92883e048 100644 --- a/ietf/doc/tests_draft.py +++ b/ietf/doc/tests_draft.py @@ -640,7 +640,7 @@ class ExpireIDsTests(DraftFileMixin, TestCase): meeting = Meeting.objects.create(number="123", type=MeetingTypeName.objects.get(slug="ietf"), - date=datetime.date.today()) + date=date_today()) second_cut_off = meeting.get_second_cut_off() ietf_monday = meeting.get_ietf_monday() diff --git a/ietf/doc/tests_irsg_ballot.py b/ietf/doc/tests_irsg_ballot.py index 97074197a..da1b48fc6 100644 --- a/ietf/doc/tests_irsg_ballot.py +++ b/ietf/doc/tests_irsg_ballot.py @@ -19,7 +19,7 @@ from ietf.doc.utils import create_ballot_if_not_open, close_ballot from ietf.person.utils import get_active_irsg, get_active_ads from ietf.group.factories import RoleFactory from ietf.person.models import Person -from ietf.utils.timezone import datetime_today, DEADLINE_TZINFO +from ietf.utils.timezone import date_today, datetime_today, DEADLINE_TZINFO class IssueIRSGBallotTests(TestCase): @@ -324,7 +324,7 @@ class BaseManipulationTests(): def test_issue_ballot(self): draft = RgDraftFactory() url = urlreverse('ietf.doc.views_ballot.issue_irsg_ballot',kwargs=dict(name=draft.name)) - due = datetime.date.today()+datetime.timedelta(days=14) + due = date_today(DEADLINE_TZINFO)+datetime.timedelta(days=14) empty_outbox() login_testing_unauthorized(self, self.username , url) @@ -445,7 +445,7 @@ class IRSGMemberTests(TestCase): def test_cant_issue_irsg_ballot(self): draft = RgDraftFactory() - due = datetime.date.today()+datetime.timedelta(days=14) + due = datetime_today(DEADLINE_TZINFO) + datetime.timedelta(days=14) url = urlreverse('ietf.doc.views_ballot.close_irsg_ballot', kwargs=dict(name=draft.name)) self.client.login(username = self.username, password = self.username+'+password') diff --git a/ietf/doc/tests_review.py b/ietf/doc/tests_review.py index 6ff804af3..8e3fdcf22 100644 --- a/ietf/doc/tests_review.py +++ b/ietf/doc/tests_review.py @@ -38,7 +38,7 @@ from ietf.utils.mail import outbox, empty_outbox, parseaddr, on_behalf_of, get_p from ietf.utils.test_utils import login_testing_unauthorized, reload_db_objects from ietf.utils.test_utils import TestCase from ietf.utils.text import strip_prefix, xslugify -from ietf.utils.timezone import DEADLINE_TZINFO +from ietf.utils.timezone import date_today, DEADLINE_TZINFO from django.utils.html import escape class ReviewTests(TestCase): @@ -78,7 +78,7 @@ class ReviewTests(TestCase): r = self.client.get(url) self.assertEqual(r.status_code, 200) - deadline = datetime.date.today() + datetime.timedelta(days=10) + deadline = date_today() + datetime.timedelta(days=10) empty_outbox() @@ -268,7 +268,7 @@ class ReviewTests(TestCase): team=review_req.team, state_id='assigned', requested_rev="01", - deadline=datetime.date.today() - datetime.timedelta(days=80), + deadline=date_today() - datetime.timedelta(days=80), ) ReviewAssignmentFactory( review_request = req, @@ -526,7 +526,7 @@ class ReviewTests(TestCase): messages = r.json()["messages"] self.assertEqual(len(messages), 2) - today = datetime.date.today() + today = date_today() self.assertEqual(messages[0]["url"], "https://www.example.com/testmessage") self.assertTrue("John Doe" in messages[0]["content"]) @@ -899,7 +899,7 @@ class ReviewTests(TestCase): assignment.review_request.team.acronym, assignment.review_request.type.slug, xslugify(assignment.reviewer.person.ascii_parts()[3]), - datetime.date.today().isoformat(), + date_today().isoformat(), ] review_name = "-".join(c for c in name_components if c).lower() Document.objects.create(name=review_name,type_id='review',group=assignment.review_request.team) diff --git a/ietf/doc/tests_utils.py b/ietf/doc/tests_utils.py index 001bd9737..f5f2fdd6b 100644 --- a/ietf/doc/tests_utils.py +++ b/ietf/doc/tests_utils.py @@ -16,6 +16,7 @@ from ietf.doc.models import State, DocumentActionHolder, DocumentAuthor, Documen from ietf.doc.utils import (update_action_holders, add_state_change_event, update_documentauthors, fuzzy_find_documents, rebuild_reference_relations) from ietf.utils.draft import Draft, PlaintextDraft +from ietf.utils.timezone import date_today from ietf.utils.xmldraft import XMLDraft @@ -146,9 +147,10 @@ class ActionHoldersTests(TestCase): dah.time_added = datetime.datetime(2020, 1, 1, tzinfo=datetime.timezone.utc) # arbitrary date in the past dah.save() - self.assertNotEqual(doc.documentactionholder_set.get(person=self.ad).time_added.date(), datetime.date.today()) + today = date_today() + self.assertNotEqual(doc.documentactionholder_set.get(person=self.ad).time_added.date(), today) self.update_doc_state(doc, State.objects.get(slug='ad-eval')) - self.assertEqual(doc.documentactionholder_set.get(person=self.ad).time_added.date(), datetime.date.today()) + self.assertEqual(doc.documentactionholder_set.get(person=self.ad).time_added.date(), today) def test_update_action_holders_add_tag_need_rev(self): """Adding need-rev tag adds authors as action holders""" diff --git a/ietf/doc/utils.py b/ietf/doc/utils.py index d74f675a8..65666ab6c 100644 --- a/ietf/doc/utils.py +++ b/ietf/doc/utils.py @@ -732,7 +732,7 @@ def update_telechat(request, doc, by, new_telechat_date, new_returning_item=None e.save() - has_short_fuse = doc.type_id=='draft' and new_telechat_date and (( new_telechat_date - datetime.date.today() ) < datetime.timedelta(days=13)) + has_short_fuse = doc.type_id=='draft' and new_telechat_date and (( new_telechat_date - date_today() ) < datetime.timedelta(days=13)) from ietf.doc.mails import email_update_telechat diff --git a/ietf/doc/utils_charter.py b/ietf/doc/utils_charter.py index 43982deab..d14684d42 100644 --- a/ietf/doc/utils_charter.py +++ b/ietf/doc/utils_charter.py @@ -25,6 +25,8 @@ from ietf.utils.mail import parse_preformatted from ietf.mailtrigger.utils import gather_address_lists from ietf.utils.log import log from ietf.group.utils import save_group_in_history +from ietf.utils.timezone import date_today + def charter_name_for_group(group): if group.type_id == "rg": @@ -216,7 +218,7 @@ def default_review_text(group, charter, by): parent_ads=group.parent.role_set.filter(name='ad'), techadv=group.role_set.filter(name="techadv"), milestones=group.groupmilestone_set.filter(state="charter"), - review_date=(datetime.date.today() + datetime.timedelta(weeks=1)).isoformat(), + review_date=(date_today() + datetime.timedelta(weeks=1)).isoformat(), review_type="new" if group.state_id in ["proposed","bof"] else "recharter", to=addrs.to, cc=addrs.cc, diff --git a/ietf/doc/utils_search.py b/ietf/doc/utils_search.py index 67024ed05..0353d5296 100644 --- a/ietf/doc/utils_search.py +++ b/ietf/doc/utils_search.py @@ -14,6 +14,8 @@ from ietf.doc.expire import expirable_drafts from ietf.doc.utils import augment_docs_and_user_with_user_info from ietf.meeting.models import SessionPresentation, Meeting, Session from ietf.review.utils import review_assignments_to_list_for_docs +from ietf.utils.timezone import date_today + def wrap_value(v): return lambda: v @@ -34,8 +36,9 @@ def fill_in_telechat_date(docs, doc_dict=None, doc_ids=None): seen.add(e.doc_id) def fill_in_document_sessions(docs, doc_dict, doc_ids): - beg_date = datetime.date.today()-datetime.timedelta(days=7) - end_date = datetime.date.today()+datetime.timedelta(days=30) + today = date_today() + beg_date = today-datetime.timedelta(days=7) + end_date = today+datetime.timedelta(days=30) meetings = Meeting.objects.filter(date__gte=beg_date, date__lte=end_date).prefetch_related('session_set') # get sessions sessions = Session.objects.filter(meeting_id__in=[ m.id for m in meetings ]) diff --git a/ietf/doc/views_ballot.py b/ietf/doc/views_ballot.py index bd6c67737..207b8b972 100644 --- a/ietf/doc/views_ballot.py +++ b/ietf/doc/views_ballot.py @@ -1084,7 +1084,7 @@ def make_last_call(request, name): return HttpResponseRedirect(doc.get_absolute_url()) else: initial = {} - initial["last_call_sent_date"] = datetime.date.today() + initial["last_call_sent_date"] = date_today() if doc.type.slug == 'draft': # This logic is repeated in the code that edits last call text - why? expire_days = 14 @@ -1095,7 +1095,7 @@ def make_last_call(request, name): expire_days=28 templ = 'doc/status_change/make_last_call.html' - initial["last_call_expiration_date"] = datetime.date.today() + datetime.timedelta(days=expire_days) + initial["last_call_expiration_date"] = date_today() + datetime.timedelta(days=expire_days) form = MakeLastCallForm(initial=initial) @@ -1192,7 +1192,10 @@ def irsg_ballot_status(request): ballot = doc.active_ballot() if ballot: doc.ballot = ballot - doc.duedate=datetime.datetime.strftime(ballot.irsgballotdocevent.duedate, '%Y-%m-%d') + doc.duedate=datetime.datetime.strftime( + ballot.irsgballotdocevent.duedate.astimezone(DEADLINE_TZINFO), + '%Y-%m-%d', + ) docs.append(doc) diff --git a/ietf/doc/views_doc.py b/ietf/doc/views_doc.py index 35b9e78fd..bdf3b6c1a 100644 --- a/ietf/doc/views_doc.py +++ b/ietf/doc/views_doc.py @@ -34,7 +34,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import datetime import glob import io import json @@ -85,6 +84,7 @@ from ietf.utils import markup_txt, log, markdown from ietf.utils.draft import PlaintextDraft from ietf.utils.response import permission_denied from ietf.utils.text import maybe_split +from ietf.utils.timezone import date_today def render_document_top(request, doc, tab, name): @@ -186,7 +186,7 @@ def document_main(request, name, rev=None): telechat = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat") - if telechat and (not telechat.telechat_date or telechat.telechat_date < datetime.date.today()): + if telechat and (not telechat.telechat_date or telechat.telechat_date < date_today(settings.TIME_ZONE)): telechat = None @@ -1408,11 +1408,12 @@ def telechat_date(request, name): warnings = [] if e and e.telechat_date and doc.type.slug != 'charter': - if e.telechat_date==datetime.date.today(): + today = date_today(settings.TIME_ZONE) + if e.telechat_date == today: warnings.append( "This document is currently scheduled for today's telechat. " +"Please set the returning item bit carefully.") - elif e.telechat_date<datetime.date.today() and has_same_ballot(doc,e.telechat_date): + elif e.telechat_date < today and has_same_ballot(doc,e.telechat_date): initial_returning_item = True warnings.append( "This document appears to have been on a previous telechat with the same ballot, " +"so the returning item bit has been set. Clear it if that is not appropriate.") diff --git a/ietf/doc/views_review.py b/ietf/doc/views_review.py index 1d901ba8a..29cf67b8d 100644 --- a/ietf/doc/views_review.py +++ b/ietf/doc/views_review.py @@ -54,7 +54,7 @@ from ietf.utils.mail import send_mail_message from ietf.mailtrigger.utils import gather_address_lists from ietf.utils.fields import MultiEmailField from ietf.utils.response import permission_denied -from ietf.utils.timezone import DEADLINE_TZINFO +from ietf.utils.timezone import date_today, DEADLINE_TZINFO def clean_doc_revision(doc, rev): @@ -96,7 +96,7 @@ class RequestReviewForm(forms.ModelForm): def clean_deadline(self): v = self.cleaned_data.get('deadline') - if v < datetime.date.today(): + if v < date_today(DEADLINE_TZINFO): raise forms.ValidationError("Select today or a date in the future.") return v @@ -352,7 +352,7 @@ class RejectReviewerAssignmentForm(forms.Form): def reject_reviewer_assignment(request, name, assignment_id): doc = get_object_or_404(Document, name=name) review_assignment = get_object_or_404(ReviewAssignment, pk=assignment_id, state__in=["assigned", "accepted"]) - review_request_past_deadline = review_assignment.review_request.deadline < datetime.date.today() + review_request_past_deadline = review_assignment.review_request.deadline < date_today(DEADLINE_TZINFO) if not review_assignment.reviewer: return redirect(review_request, name=review_assignment.review_request.doc.name, request_id=review_assignment.review_request.pk) @@ -535,7 +535,7 @@ class CompleteReviewForm(forms.Form): review_url = forms.URLField(label="Link to message", required=False) review_file = forms.FileField(label="Text file to upload", required=False) review_content = forms.CharField(widget=forms.Textarea, required=False, strip=False) - completion_date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={ "autoclose": "1" }, initial=datetime.date.today, help_text="Date of announcement of the results of this review") + completion_date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={ "autoclose": "1" }, initial=date_today, help_text="Date of announcement of the results of this review") completion_time = forms.TimeField(widget=forms.HiddenInput, initial=datetime.time.min) cc = MultiEmailField(required=False, help_text="Email addresses to send to in addition to the review team list") email_ad = forms.BooleanField(label="Send extra email to the responsible AD suggesting early attention", required=False) @@ -708,7 +708,7 @@ def complete_review(request, name, assignment_id=None, acronym=None): team.acronym, request_type.slug, xslugify(reviewer.person.ascii_parts()[3]), - datetime.date.today().isoformat(), + date_today().isoformat(), ] review_name = "-".join(c for c in name_components if c).lower() if not Document.objects.filter(name=review_name).exists(): @@ -727,7 +727,7 @@ def complete_review(request, name, assignment_id=None, acronym=None): type=form.cleaned_data['review_type'], doc=doc, team=team, - deadline=datetime.date.today(), + deadline=date_today(DEADLINE_TZINFO), requested_by=Person.objects.get(user=request.user), requested_rev=form.cleaned_data['reviewed_rev'], ) @@ -786,7 +786,7 @@ def complete_review(request, name, assignment_id=None, acronym=None): need_to_email_review = review_submission != "link" and assignment.review_request.team.list_email and not revising_review - submitted_on_different_date = completion_datetime.date() != datetime.date.today() + submitted_on_different_date = completion_datetime.date() != date_today(DEADLINE_TZINFO) desc = "Request for {} review by {} {}: {}. Reviewer: {}.".format( assignment.review_request.type.name, assignment.review_request.team.acronym.upper(), @@ -902,8 +902,13 @@ def complete_review(request, name, assignment_id=None, acronym=None): } try: - initial['review_content'] = render_to_string('/group/%s/review/content_templates/%s.txt' % (assignment.review_request.team.acronym, - request_type.slug), {'assignment':assignment, 'today':datetime.date.today()}) + initial['review_content'] = render_to_string( + f'/group/{assignment.review_request.team.acronym}/review/content_templates/{request_type.slug}.txt', + { + 'assignment': assignment, + 'today': date_today(settings.TIME_ZONE), + }, + ) except (TemplateDoesNotExist, AttributeError): pass @@ -992,7 +997,7 @@ class EditReviewRequestDeadlineForm(forms.ModelForm): def clean_deadline(self): v = self.cleaned_data.get('deadline') - if v < datetime.date.today(): + if v < date_today(DEADLINE_TZINFO): raise forms.ValidationError("Select today or a date in the future.") return v diff --git a/ietf/doc/views_stats.py b/ietf/doc/views_stats.py index 414d04bbe..912d4a57c 100644 --- a/ietf/doc/views_stats.py +++ b/ietf/doc/views_stats.py @@ -19,6 +19,8 @@ from ietf.doc.utils import get_search_cache_key from ietf.doc.views_search import SearchForm, retrieve_search_results from ietf.name.models import DocTypeName from ietf.person.models import Person +from ietf.utils.timezone import date_today + epochday = datetime.datetime.utcfromtimestamp(0).date().toordinal() @@ -47,7 +49,7 @@ def model_to_timeline_data(model, field='time', **kwargs): # This is needed for sqlite, when we're running tests: if type(obj_list[0]['date']) != datetime.date: obj_list = [ {'date': dt(e['date']), 'count': e['count']} for e in obj_list ] - today = datetime.date.today() + today = date_today() if not obj_list[-1]['date'] == today: obj_list += [ {'date': today, 'count': 0} ] data = [ ((e['date'].toordinal()-epochday)*1000*60*60*24, e['count']) for e in obj_list ] diff --git a/ietf/doc/views_status_change.py b/ietf/doc/views_status_change.py index b64aadfd0..d4868215a 100644 --- a/ietf/doc/views_status_change.py +++ b/ietf/doc/views_status_change.py @@ -35,6 +35,7 @@ from ietf.name.models import DocRelationshipName, StdLevelName from ietf.person.models import Person from ietf.utils.mail import send_mail_preformatted from ietf.utils.textupload import get_cleaned_text_file_content +from ietf.utils.timezone import date_today, DEADLINE_TZINFO class ChangeStateForm(forms.Form): @@ -638,7 +639,7 @@ def generate_last_call_text(request, doc): # and when groups are set, vary the expiration time accordingly requester = "an individual participant" - expiration_date = datetime.date.today() + datetime.timedelta(days=28) + expiration_date = date_today(DEADLINE_TZINFO) + datetime.timedelta(days=28) cc = [] new_text = render_to_string("doc/status_change/last_call_announcement.txt", diff --git a/ietf/group/forms.py b/ietf/group/forms.py index 0b8fc8e45..c93ca1d63 100644 --- a/ietf/group/forms.py +++ b/ietf/group/forms.py @@ -3,7 +3,6 @@ # Stdlib imports -import datetime import re import debug # pyflakes:ignore @@ -27,6 +26,7 @@ from ietf.utils import log from ietf.utils.textupload import get_cleaned_text_file_content #from ietf.utils.ordereddict import insert_after_in_ordered_dict from ietf.utils.fields import DatepickerDateField, MultiEmailField +from ietf.utils.timezone import date_today from ietf.utils.validators import validate_external_resource_value # --- Constants -------------------------------------------------------- @@ -364,7 +364,7 @@ class AddUnavailablePeriodForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(AddUnavailablePeriodForm, self).__init__(*args, **kwargs) - self.fields["start_date"] = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label=self.fields["start_date"].label, help_text=self.fields["start_date"].help_text, required=self.fields["start_date"].required, initial=datetime.date.today()) + self.fields["start_date"] = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label=self.fields["start_date"].label, help_text=self.fields["start_date"].help_text, required=self.fields["start_date"].required, initial=date_today()) self.fields["end_date"] = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label=self.fields["end_date"].label, help_text=self.fields["end_date"].help_text, required=self.fields["end_date"].required) self.fields['availability'].widget = forms.RadioSelect(choices=UnavailablePeriod.LONG_AVAILABILITY_CHOICES) diff --git a/ietf/group/tests_info.py b/ietf/group/tests_info.py index 932b0594e..9d5328d51 100644 --- a/ietf/group/tests_info.py +++ b/ietf/group/tests_info.py @@ -42,6 +42,8 @@ from ietf.person.factories import PersonFactory, EmailFactory from ietf.review.factories import ReviewRequestFactory, ReviewAssignmentFactory from ietf.utils.mail import outbox, empty_outbox, get_payload_text from ietf.utils.test_utils import login_testing_unauthorized, TestCase, unicontent, reload_db_objects +from ietf.utils.timezone import date_today, DEADLINE_TZINFO + def group_urlreverse_list(group, viewname): return [ @@ -269,7 +271,7 @@ class GroupPagesTests(TestCase): group=group, state_id="active", desc="Get Work Done", - due=datetime.date.today() + datetime.timedelta(days=100)) + due=date_today(DEADLINE_TZINFO) + datetime.timedelta(days=100)) milestone.docs.add(draft) for url in [group.about_url(),] + group_urlreverse_list(group, 'ietf.group.views.group_about'): @@ -876,7 +878,7 @@ class GroupEditTests(TestCase): self.assertEqual(r.status_code, 302) review_assignment.state_id = 'accepted' review_assignment.save() - review_req.deadline = datetime.date.today() - datetime.timedelta(days=1) + review_req.deadline = date_today(DEADLINE_TZINFO) - datetime.timedelta(days=1) review_req.save() r = self.client.post(url, post_data) @@ -1194,7 +1196,7 @@ class MilestoneTests(TestCase): m1 = GroupMilestone.objects.create(id=1, group=group, desc="Test 1", - due=datetime.date.today(), + due=date_today(DEADLINE_TZINFO), resolved="", state_id="active") m1.docs.set([draft]) @@ -1202,7 +1204,7 @@ class MilestoneTests(TestCase): m2 = GroupMilestone.objects.create(id=2, group=group, desc="Test 2", - due=datetime.date.today(), + due=date_today(DEADLINE_TZINFO), resolved="", state_id="charter") m2.docs.set([draft]) @@ -1246,7 +1248,7 @@ class MilestoneTests(TestCase): events_before = group.groupevent_set.count() doc_pks = pklist(Document.objects.filter(type="draft")) - due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365)) + due = self.last_day_of_month(date_today(DEADLINE_TZINFO) + datetime.timedelta(days=365)) # faulty post r = self.client.post(url, { 'prefix': "m-1", @@ -1302,7 +1304,7 @@ class MilestoneTests(TestCase): milestones_before = GroupMilestone.objects.filter(group=group).count() events_before = group.groupevent_set.count() - due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365)) + due = self.last_day_of_month(date_today(DEADLINE_TZINFO) + datetime.timedelta(days=365)) # add mailbox_before = len(outbox) @@ -1393,7 +1395,7 @@ class MilestoneTests(TestCase): events_before = group.groupevent_set.count() doc_pks = pklist(Document.objects.filter(type="draft")) - due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365)) + due = self.last_day_of_month(date_today(DEADLINE_TZINFO) + datetime.timedelta(days=365)) # faulty post r = self.client.post(url, { 'prefix': "m1", @@ -1776,7 +1778,7 @@ class MeetingInfoTests(TestCase): def setUp(self): super().setUp() self.group = GroupFactory.create(type_id='wg') - today = datetime.date.today() + today = date_today() SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=14)) self.inprog = SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=1)) SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today+datetime.timedelta(days=90)) @@ -1900,7 +1902,7 @@ class StatusUpdateTests(TestCase): def test_view_status_update_for_meeting(self): chair = RoleFactory(name_id='chair',group__type_id='wg') GroupEventFactory(type='status_update',group=chair.group) - sess = SessionFactory.create(meeting__type_id='ietf',group=chair.group,meeting__date=timezone.now()-datetime.timedelta(days=1)) + sess = SessionFactory.create(meeting__type_id='ietf',group=chair.group,meeting__date=date_today()-datetime.timedelta(days=1)) url = urlreverse('ietf.group.views.group_about_status_meeting',kwargs={'acronym':chair.group.acronym,'num':sess.meeting.number}) response = self.client.get(url) self.assertEqual(response.status_code,200) diff --git a/ietf/group/tests_js.py b/ietf/group/tests_js.py index 49dd33983..1c7f9fc9a 100644 --- a/ietf/group/tests_js.py +++ b/ietf/group/tests_js.py @@ -7,6 +7,7 @@ import debug # pyflakes:ignore from ietf.doc.factories import WgDraftFactory from ietf.group.factories import GroupFactory, RoleFactory, DatedGroupMilestoneFactory from ietf.utils.jstest import IetfSeleniumTestCase, ifSeleniumEnabled, selenium_enabled +from ietf.utils.timezone import date_today if selenium_enabled(): from selenium.common.exceptions import TimeoutException @@ -68,7 +69,7 @@ class MilestoneTests(IetfSeleniumTestCase): draft = WgDraftFactory() WgDraftFactory.create_batch(3) # some drafts to ignore description = 'some description' - due_date = datetime.date.today() + datetime.timedelta(days=60) + due_date = date_today() + datetime.timedelta(days=60) assert(len(draft.name) > 5) draft_search_string = draft.name[-5:] diff --git a/ietf/group/tests_review.py b/ietf/group/tests_review.py index 4930c740c..fc09e27e0 100644 --- a/ietf/group/tests_review.py +++ b/ietf/group/tests_review.py @@ -7,6 +7,7 @@ import debug # pyflakes:ignore from pyquery import PyQuery +from django.conf import settings from django.urls import reverse as urlreverse from django.utils import timezone @@ -477,7 +478,7 @@ class ReviewTests(TestCase): review_req1 = ReviewRequestFactory() review_assignment_completed = ReviewAssignmentFactory(review_request=review_req1,reviewer=EmailFactory(person__user__username='marschairman'), state_id='completed', reviewed_rev=0) ReviewAssignmentFactory(review_request=review_req1,reviewer=review_assignment_completed.reviewer) - TelechatDocEvent.objects.create(telechat_date=datetime.date.today(), type='scheduled_for_telechat', by=review_assignment_completed.reviewer.person, doc=review_req1.doc, rev=0) + TelechatDocEvent.objects.create(telechat_date=date_today(settings.TIME_ZONE), type='scheduled_for_telechat', by=review_assignment_completed.reviewer.person, doc=review_req1.doc, rev=0) DBTemplateFactory.create(path='/group/defaults/email/open_assignments.txt', type_id='django', @@ -557,7 +558,7 @@ class ReviewTests(TestCase): # get r = self.client.get(url) self.assertEqual(r.status_code, 200) - self.assertEqual(r.context['period_form']['start_date'].initial, datetime.date.today()) + self.assertEqual(r.context['period_form']['start_date'].initial, date_today()) # set settings empty_outbox() @@ -598,7 +599,7 @@ class ReviewTests(TestCase): self.assertEqual(settings.skip_next, 0) # add unavailable period - start_date = datetime.date.today() + datetime.timedelta(days=10) + start_date = date_today() + datetime.timedelta(days=10) empty_outbox() r = self.client.post(url, { "action": "add_period", diff --git a/ietf/group/views.py b/ietf/group/views.py index d003c44a9..4bc31d09f 100644 --- a/ietf/group/views.py +++ b/ietf/group/views.py @@ -119,7 +119,7 @@ from ietf.settings import MAILING_LIST_INFO_URL from ietf.utils.response import permission_denied from ietf.utils.text import strip_suffix from ietf.utils import markdown -from ietf.utils.timezone import datetime_today, DEADLINE_TZINFO +from ietf.utils.timezone import date_today, datetime_today, DEADLINE_TZINFO # --- Helpers ---------------------------------------------------------- @@ -1028,7 +1028,7 @@ def edit(request, group_type=None, acronym=None, action="edit", field=None): change_text=title + ' deleted: ' + ", ".join(x.name_and_email() for x in deleted) personnel_change_text+=change_text+"\n" - today = datetime.date.today() + today = date_today() for deleted_email in deleted: # Verify the person doesn't have a separate reviewer role for the group with a different address if not group.role_set.filter(name_id='reviewer',person=deleted_email.person).exists(): @@ -1389,7 +1389,7 @@ def review_requests(request, acronym, group_type=None): unassigned_review_requests.sort(key=lambda r: r.doc.name) open_review_assignments = list(ReviewAssignment.objects.filter(review_request__team=group, state_id__in=('assigned','accepted')).order_by('-assigned_on')) - today = datetime.date.today() + today = date_today(DEADLINE_TZINFO) unavailable_periods = current_unavailable_periods_for_reviewers(group) for a in open_review_assignments: a.reviewer_unavailable = any(p.availability == "unavailable" @@ -1460,7 +1460,7 @@ def reviewer_overview(request, acronym, group_type=None): unavailable_periods[p.person_id].append(p) reviewer_roles = { r.person_id: r for r in Role.objects.filter(group=group, name="reviewer").select_related("email") } - today = datetime.date.today() + today = date_today() max_closed_reqs = settings.GROUP_REVIEW_MAX_ITEMS_TO_SHOW_IN_REVIEWER_LIST days_back = settings.GROUP_REVIEW_DAYS_TO_SHOW_IN_REVIEWER_LIST @@ -1838,7 +1838,7 @@ def change_reviewer_settings(request, acronym, reviewer_email, group_type=None): period.save() update_change_reason(period, "Added unavailability period: {}".format(period)) - today = datetime.date.today() + today = date_today() in_the_past = period.end_date and period.end_date < today @@ -1879,7 +1879,7 @@ def change_reviewer_settings(request, acronym, reviewer_email, group_type=None): period.delete() update_change_reason(period, "Removed unavailability period: {}".format(period)) - today = datetime.date.today() + today = date_today() in_the_past = period.end_date and period.end_date < today diff --git a/ietf/idindex/index.py b/ietf/idindex/index.py index 782e8912e..d864905e4 100644 --- a/ietf/idindex/index.py +++ b/ietf/idindex/index.py @@ -7,7 +7,6 @@ import datetime import os -import pytz from django.conf import settings from django.template.loader import render_to_string @@ -297,6 +296,6 @@ def id_index_txt(with_abstracts=False): return render_to_string("idindex/id_index.txt", { 'groups': groups, - 'time': timezone.now().astimezone(pytz.utc).strftime("%Y-%m-%d %H:%M:%S %Z"), + 'time': timezone.now().astimezone(datetime.timezone.utc).strftime("%Y-%m-%d %H:%M:%S %Z"), 'with_abstracts': with_abstracts, }) diff --git a/ietf/iesg/agenda.py b/ietf/iesg/agenda.py index e923c1bab..113c3c5d1 100644 --- a/ietf/iesg/agenda.py +++ b/ietf/iesg/agenda.py @@ -17,13 +17,14 @@ from ietf.doc.models import Document, LastCallDocEvent, ConsensusDocEvent from ietf.doc.utils_search import fill_in_telechat_date from ietf.iesg.models import TelechatDate, TelechatAgendaItem from ietf.review.utils import review_assignments_to_list_for_docs +from ietf.utils.timezone import date_today def get_agenda_date(date=None): if not date: try: return TelechatDate.objects.active().order_by('date')[0].date except IndexError: - return datetime.date.today() + return date_today() else: try: return TelechatDate.objects.active().get(date=datetime.datetime.strptime(date, "%Y-%m-%d").date()).date diff --git a/ietf/iesg/feeds.py b/ietf/iesg/feeds.py index 6e8d290c6..a8b5c2869 100644 --- a/ietf/iesg/feeds.py +++ b/ietf/iesg/feeds.py @@ -2,12 +2,13 @@ # -*- coding: utf-8 -*- -import datetime - +from django.conf import settings from django.contrib.syndication.views import Feed from django.utils.feedgenerator import Atom1Feed from ietf.doc.models import Document, TelechatDocEvent +from ietf.utils.timezone import date_today + class IESGAgendaFeed(Feed): title = "Documents on Future IESG Telechat Agendas" @@ -16,7 +17,7 @@ class IESGAgendaFeed(Feed): description_template = "iesg/feed_item_description.html" def items(self): - docs = Document.objects.filter(docevent__telechatdocevent__telechat_date__gte=datetime.date.today()).distinct() + docs = Document.objects.filter(docevent__telechatdocevent__telechat_date__gte=date_today(settings.TIME_ZONE)).distinct() for d in docs: d.latest_telechat_event = d.latest_event(TelechatDocEvent, type="scheduled_for_telechat") docs = [d for d in docs if d.latest_telechat_event.telechat_date] diff --git a/ietf/iesg/models.py b/ietf/iesg/models.py index f3690d4c7..6a622e27e 100644 --- a/ietf/iesg/models.py +++ b/ietf/iesg/models.py @@ -36,8 +36,12 @@ import datetime +from django.conf import settings from django.db import models +from ietf.utils.timezone import date_today + + class TelechatAgendaItem(models.Model): TYPE_CHOICES = ( (1, "Any Other Business (WG News, New Proposals, etc.)"), @@ -72,11 +76,11 @@ def next_telechat_date(): dates = TelechatDate.objects.order_by("-date") if dates: return dates[0].date + datetime.timedelta(days=14) - return datetime.date.today() + return date_today(settings.TIME_ZONE) class TelechatDateManager(models.Manager): def active(self): - return self.get_queryset().filter(date__gte=datetime.date.today()) + return self.get_queryset().filter(date__gte=date_today(settings.TIME_ZONE)) class TelechatDate(models.Model): objects = TelechatDateManager() diff --git a/ietf/iesg/tests.py b/ietf/iesg/tests.py index f317ad32b..5ecb4ed9d 100644 --- a/ietf/iesg/tests.py +++ b/ietf/iesg/tests.py @@ -28,6 +28,7 @@ from ietf.name.models import StreamName from ietf.person.models import Person from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent from ietf.iesg.factories import IESGMgmtItemFactory +from ietf.utils.timezone import date_today, DEADLINE_TZINFO class IESGTests(TestCase): @@ -58,7 +59,7 @@ class IESGTests(TestCase): m = GroupMilestone.objects.create(group=draft.group, state_id="review", desc="Test milestone", - due=datetime.date.today()) + due=date_today(DEADLINE_TZINFO)) url = urlreverse("ietf.iesg.views.milestones_needing_review") login_testing_unauthorized(self, "ad", url) @@ -142,7 +143,7 @@ class IESGAgendaTests(TestCase): mgmtitem = self.mgmt_items # put on agenda - date = datetime.date.today() + datetime.timedelta(days=50) + date = date_today(settings.TIME_ZONE) + datetime.timedelta(days=50) TelechatDate.objects.create(date=date) telechat_event = TelechatDocEvent.objects.create( type="scheduled_for_telechat", @@ -430,7 +431,7 @@ class IESGAgendaTests(TestCase): self.assertNotIn(d.title, unicontent(r)) # Add the documents to a past telechat by = Person.objects.get(name="Areaư Irector") - date = datetime.date.today() - datetime.timedelta(days=14) + date = date_today(settings.TIME_ZONE) - datetime.timedelta(days=14) approved = State.objects.get(type='draft-iesg', slug='approved') iesg_eval = State.objects.get(type='draft-iesg', slug='iesg-eva') for d in list(self.telechat_docs.values()): @@ -485,7 +486,7 @@ class IESGAgendaTests(TestCase): def test_admin_change(self): draft = Document.objects.get(name="draft-ietf-mars-test") - today = datetime.date.today() + today = date_today(settings.TIME_ZONE) telechat_date = TelechatDate.objects.get(date=draft.telechat_date()) url = urlreverse('admin:iesg_telechatdate_change', args=(telechat_date.id,)) self.client.login(username="secretary", password="secretary+password") diff --git a/ietf/ietfauth/tests.py b/ietf/ietfauth/tests.py index f6bacdcb1..e2b842a86 100644 --- a/ietf/ietfauth/tests.py +++ b/ietf/ietfauth/tests.py @@ -47,6 +47,8 @@ from ietf.stats.models import MeetingRegistration from ietf.utils.decorators import skip_coverage from ietf.utils.mail import outbox, empty_outbox, get_payload_text from ietf.utils.test_utils import TestCase, login_testing_unauthorized +from ietf.utils.timezone import date_today + import ietf.ietfauth.views @@ -392,7 +394,7 @@ class IetfAuthTests(TestCase): self.assertFalse(q('#volunteer-button')) self.assertFalse(q('#volunteered')) - year = datetime.date.today().year + year = date_today().year nomcom = NomComFactory(group__acronym=f'nomcom{year}',is_accepting_volunteers=True) r = self.client.get(url) self.assertEqual(r.status_code,200) @@ -507,7 +509,7 @@ class IetfAuthTests(TestCase): UnavailablePeriod.objects.create( team=review_req.team, person=reviewer, - start_date=datetime.date.today() - datetime.timedelta(days=10), + start_date=date_today() - datetime.timedelta(days=10), availability="unavailable", ) @@ -790,7 +792,7 @@ class IetfAuthTests(TestCase): for i in range(count): for key in person.apikeys.all(): self.client.post(key.endpoint, {'apikey':key.hash(), 'dummy': 'dummy', }) - date = str(datetime.date.today()) + date = str(date_today()) empty_outbox() cmd = Command() @@ -907,7 +909,7 @@ class OpenIDConnectTests(TestCase): # an additional email EmailFactory(person=person) email_list = person.email_set.all().values_list('address', flat=True) - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today()) + meeting = MeetingFactory(type_id='ietf', date=date_today()) MeetingRegistration.objects.create( meeting=meeting, person=None, first_name=person.first_name(), last_name=person.last_name(), email=email_list[0], ticket_type='full_week', reg_type='remote', affiliation='Some Company', diff --git a/ietf/ipr/tests.py b/ietf/ipr/tests.py index de52c773a..ab6b01a5b 100644 --- a/ietf/ipr/tests.py +++ b/ietf/ipr/tests.py @@ -28,6 +28,7 @@ from ietf.message.models import Message from ietf.utils.mail import outbox, empty_outbox, get_payload_text from ietf.utils.test_utils import TestCase, login_testing_unauthorized from ietf.utils.text import text_to_dict +from ietf.utils.timezone import date_today def make_data_from_content(content): @@ -573,7 +574,7 @@ I would like to revoke this declaration. self.assertEqual(r.status_code,302) self.assertEqual(len(outbox),len_before+2) self.assertTrue('george@acme.com' in outbox[len_before]['To']) - self.assertIn('posted on '+datetime.date.today().strftime("%Y-%m-%d"), get_payload_text(outbox[len_before]).replace('\n',' ')) + self.assertIn('posted on '+date_today().strftime("%Y-%m-%d"), get_payload_text(outbox[len_before]).replace('\n',' ')) self.assertTrue('draft-ietf-mars-test@ietf.org' in outbox[len_before+1]['To']) self.assertTrue('mars-wg@ietf.org' in outbox[len_before+1]['Cc']) self.assertIn('Secretariat on '+ipr.get_latest_event_submitted().time.strftime("%Y-%m-%d"), get_payload_text(outbox[len_before+1]).replace('\n',' ')) @@ -601,7 +602,7 @@ I would like to revoke this declaration. ipr = HolderIprDisclosureFactory() url = urlreverse('ietf.ipr.views.email',kwargs={ "id": ipr.id }) self.client.login(username="secretary", password="secretary+password") - yesterday = datetime.date.today() - datetime.timedelta(1) + yesterday = date_today() - datetime.timedelta(1) data = dict( to='joe@test.com', frm='ietf-ipr@ietf.org', diff --git a/ietf/liaisons/forms.py b/ietf/liaisons/forms.py index 3f46b4320..b76551953 100644 --- a/ietf/liaisons/forms.py +++ b/ietf/liaisons/forms.py @@ -226,7 +226,7 @@ class LiaisonModelForm(BetterModelForm): to_groups.widget.attrs['data-minimum-input-length'] = 0 deadline = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='Deadline', required=True) related_to = SearchableLiaisonStatementsField(label='Related Liaison Statement', required=False) - submitted_date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='Submission date', required=True, initial=date_today(DEADLINE_TZINFO)) + submitted_date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='Submission date', required=True, initial=lambda: date_today(DEADLINE_TZINFO)) attachments = CustomModelMultipleChoiceField(queryset=Document.objects,label='Attachments', widget=ShowAttachmentsWidget, required=False) attach_title = forms.CharField(label='Title', required=False) attach_file = forms.FileField(label='File', required=False) diff --git a/ietf/liaisons/mails.py b/ietf/liaisons/mails.py index 47f18c75b..8708c8a07 100644 --- a/ietf/liaisons/mails.py +++ b/ietf/liaisons/mails.py @@ -2,14 +2,14 @@ # -*- coding: utf-8 -*- -import datetime - from django.conf import settings from django.template.loader import render_to_string from ietf.utils.mail import send_mail_text from ietf.group.models import Role from ietf.mailtrigger.utils import gather_address_lists +from ietf.utils.timezone import date_today, DEADLINE_TZINFO + def send_liaison_by_email(request, liaison): subject = 'New Liaison Statement, "%s"' % (liaison.title) @@ -61,7 +61,7 @@ def possibly_send_deadline_reminder(liaison): 0: 'today' } - days_to_go = (liaison.deadline - datetime.date.today()).days + days_to_go = (liaison.deadline - date_today(DEADLINE_TZINFO)).days if not (days_to_go < 0 or days_to_go in list(PREVIOUS_DAYS.keys())): return None # no reminder diff --git a/ietf/liaisons/management/commands/check_liaison_deadlines.py b/ietf/liaisons/management/commands/check_liaison_deadlines.py index 84faa5fed..1fe76029a 100644 --- a/ietf/liaisons/management/commands/check_liaison_deadlines.py +++ b/ietf/liaisons/management/commands/check_liaison_deadlines.py @@ -8,13 +8,14 @@ from django.core.management.base import BaseCommand from ietf.liaisons.models import LiaisonStatement from ietf.liaisons.mails import possibly_send_deadline_reminder +from ietf.utils.timezone import date_today, DEADLINE_TZINFO class Command(BaseCommand): help = ("Check liaison deadlines and send a reminder if we are close to a deadline") def handle(self, *args, **options): - today = datetime.date.today() + today = date_today(DEADLINE_TZINFO) cutoff = today - datetime.timedelta(14) msgs = [] diff --git a/ietf/liaisons/tests.py b/ietf/liaisons/tests.py index f65b18c67..845271db7 100644 --- a/ietf/liaisons/tests.py +++ b/ietf/liaisons/tests.py @@ -31,6 +31,8 @@ from ietf.person.models import Person from ietf.group.models import Group from ietf.liaisons.mails import send_sdo_reminder, possibly_send_deadline_reminder from ietf.liaisons.views import contacts_from_roles, contact_email_from_role +from ietf.utils.timezone import date_today, DEADLINE_TZINFO + # ------------------------------------------------- # Helper Functions @@ -244,7 +246,7 @@ class ManagementCommandTests(TestCase): def test_check_liaison_deadlines(self): from django.core.management import call_command - LiaisonStatementFactory(deadline=datetime.date.today()+datetime.timedelta(days=1)) + LiaisonStatementFactory(deadline=date_today(DEADLINE_TZINFO)+datetime.timedelta(days=1)) out = io.StringIO() mailbox_before = len(outbox) @@ -312,7 +314,7 @@ class LiaisonManagementTests(TestCase): self.assertNotContains(r, 'Private comment') def test_taken_care_of(self): - liaison = LiaisonStatementFactory(deadline=datetime.date.today()+datetime.timedelta(days=1)) + liaison = LiaisonStatementFactory(deadline=date_today(DEADLINE_TZINFO)+datetime.timedelta(days=1)) url = urlreverse('ietf.liaisons.views.liaison_detail', kwargs=dict(object_id=liaison.pk)) # normal get @@ -386,7 +388,7 @@ class LiaisonManagementTests(TestCase): self.assertTrue(liaison.liaisonstatementevent_set.filter(type='posted')) def test_edit_liaison(self): - liaison = LiaisonStatementFactory(deadline=datetime.date.today()+datetime.timedelta(days=1)) + liaison = LiaisonStatementFactory(deadline=date_today(DEADLINE_TZINFO) + datetime.timedelta(days=1)) LiaisonStatementEventFactory(statement=liaison,type_id='submitted', time=timezone.now()-datetime.timedelta(days=1)) LiaisonStatementEventFactory(statement=liaison,type_id='posted') from_group = liaison.from_groups.first() @@ -698,7 +700,7 @@ class LiaisonManagementTests(TestCase): from_groups = [ str(g.pk) for g in Group.objects.filter(type="sdo") ] to_group = Group.objects.get(acronym="mars") submitter = Person.objects.get(user__username="marschairman") - today = datetime.date.today() + today = date_today() related_liaison = liaison r = self.client.post(url, dict(from_groups=from_groups, @@ -777,7 +779,7 @@ class LiaisonManagementTests(TestCase): from_group = Group.objects.get(acronym="mars") to_group = Group.objects.filter(type="sdo")[0] submitter = Person.objects.get(user__username="marschairman") - today = datetime.date.today() + today = date_today() related_liaison = liaison r = self.client.post(url, dict(from_groups=str(from_group.pk), @@ -845,7 +847,7 @@ class LiaisonManagementTests(TestCase): from_group = Group.objects.get(acronym="mars") to_group = Group.objects.filter(type="sdo")[0] submitter = Person.objects.get(user__username="marschairman") - today = datetime.date.today() + today = date_today() r = self.client.post(url, dict(from_groups=str(from_group.pk), from_contact=submitter.email_address(), @@ -864,7 +866,7 @@ class LiaisonManagementTests(TestCase): self.assertEqual(len(outbox), mailbox_before + 1) def test_liaison_add_attachment(self): - liaison = LiaisonStatementFactory(deadline=datetime.date.today()+datetime.timedelta(days=1)) + liaison = LiaisonStatementFactory(deadline=date_today()+datetime.timedelta(days=1)) LiaisonStatementEventFactory(statement=liaison,type_id='submitted') self.assertEqual(liaison.attachments.count(),0) @@ -1150,7 +1152,7 @@ class LiaisonManagementTests(TestCase): self.assertTrue('ulm-liaiman@' in outbox[-1]['To']) def test_send_liaison_deadline_reminder(self): - liaison = LiaisonStatementFactory(deadline=datetime.date.today()+datetime.timedelta(days=1)) + liaison = LiaisonStatementFactory(deadline=date_today(DEADLINE_TZINFO) + datetime.timedelta(days=1)) mailbox_before = len(outbox) possibly_send_deadline_reminder(liaison) diff --git a/ietf/meeting/management/commands/meetecho_conferences.py b/ietf/meeting/management/commands/meetecho_conferences.py index e6525d7dc..8a7eb0ebc 100644 --- a/ietf/meeting/management/commands/meetecho_conferences.py +++ b/ietf/meeting/management/commands/meetecho_conferences.py @@ -1,7 +1,5 @@ # Copyright The IETF Trust 2022, All Rights Reserved # -*- coding: utf-8 -*- -import datetime - from textwrap import dedent from django.conf import settings @@ -9,6 +7,7 @@ from django.core.management.base import BaseCommand, CommandError from ietf.meeting.models import Session from ietf.utils.meetecho import ConferenceManager, MeetechoAPIError +from ietf.utils.timezone import date_today class Command(BaseCommand): @@ -85,7 +84,7 @@ class Command(BaseCommand): for conf in confs: conf_sessions[conf.id] = Session.objects.filter( group__acronym=group, - meeting__date__gte=datetime.date.today(), + meeting__date__gte=date_today(), remote_instructions__contains=conf.url, ) return confs, conf_sessions diff --git a/ietf/meeting/management/commands/update_important_dates.py b/ietf/meeting/management/commands/update_important_dates.py index c1a6ad424..9a06e850a 100644 --- a/ietf/meeting/management/commands/update_important_dates.py +++ b/ietf/meeting/management/commands/update_important_dates.py @@ -11,6 +11,8 @@ import debug # pyflakes:ignore from ietf.name.models import ImportantDateName from ietf.meeting.helpers import update_important_dates from ietf.meeting.models import Meeting, ImportantDate +from ietf.utils.timezone import date_today + class Command(BaseCommand): @@ -29,7 +31,7 @@ class Command(BaseCommand): if not meeting: self.stderr.write("\nMeeting not found: %s\n" % (m, )) continue - if meeting.date < datetime.date.today() + datetime.timedelta(days=max_offset): + if meeting.date < date_today(meeting.tz()) + datetime.timedelta(days=max_offset): self.stderr.write("\nMeeting %s: Won't change dates for meetings in the past or close future\n" % (meeting, )) continue self.stdout.write('\n%s\n\n' % (meeting, )) diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py index 4bcb21f44..83b245f76 100644 --- a/ietf/meeting/models.py +++ b/ietf/meeting/models.py @@ -41,7 +41,7 @@ from ietf.person.models import Person from ietf.utils.decorators import memoize from ietf.utils.storage import NoLocationMigrationFileSystemStorage from ietf.utils.text import xslugify -from ietf.utils.timezone import datetime_from_date +from ietf.utils.timezone import datetime_from_date, date_today from ietf.utils.models import ForeignKey from ietf.utils.validators import ( MaxImageSizeValidator, WrappedValidator, validate_file_size, validate_mime_type, @@ -147,7 +147,12 @@ class Meeting(models.Model): return datetime_from_date(self.get_meeting_date(self.days), self.tz()) def get_00_cutoff(self): - start_date = datetime.datetime(year=self.date.year, month=self.date.month, day=self.date.day, tzinfo=pytz.utc) + start_date = datetime.datetime( + year=self.date.year, + month=self.date.month, + day=self.date.day, + tzinfo=datetime.timezone.utc, + ) importantdate = self.importantdate_set.filter(name_id='idcutoff').first() if not importantdate: importantdate = self.importantdate_set.filter(name_id='00cutoff').first() @@ -745,7 +750,7 @@ class Schedule(models.Model): @property def is_official_record(self): return (self.is_official and - self.meeting.end_date() <= datetime.date.today() ) + self.meeting.end_date() <= date_today() ) # returns a dictionary {group -> [schedtimesessassignment+]} # and it has [] if the session is not placed. @@ -1162,7 +1167,7 @@ class Session(models.Model): return can_manage_materials(user,self.group) def is_material_submission_cutoff(self): - return datetime.date.today() > self.meeting.get_submission_correction_date() + return date_today(self.meeting.tz()) > self.meeting.get_submission_correction_date() def joint_with_groups_acronyms(self): return [group.acronym for group in self.joint_with_groups.all()] diff --git a/ietf/meeting/test_data.py b/ietf/meeting/test_data.py index 9fd49f1c8..5ecb494df 100644 --- a/ietf/meeting/test_data.py +++ b/ietf/meeting/test_data.py @@ -20,6 +20,8 @@ from ietf.name.models import RoomResourceName from ietf.person.factories import PersonFactory from ietf.person.models import Person from ietf.utils.test_data import make_test_data +from ietf.utils.timezone import date_today + def make_interim_meeting(group,date,status='sched',tz='UTC'): system_person = Person.objects.get(name="(System)") @@ -216,8 +218,8 @@ def make_meeting_test_data(meeting=None, create_interims=False): mars_session.sessionpresentation_set.add(pres) # Future Interim Meetings - date = datetime.date.today() + datetime.timedelta(days=365) - date2 = datetime.date.today() + datetime.timedelta(days=1000) + date = date_today() + datetime.timedelta(days=365) + date2 = date_today() + datetime.timedelta(days=1000) ames = Group.objects.get(acronym="ames") if create_interims: @@ -229,8 +231,8 @@ def make_meeting_test_data(meeting=None, create_interims=False): return meeting def make_interim_test_data(meeting_tz='UTC'): - date = datetime.date.today() + datetime.timedelta(days=365) - date2 = datetime.date.today() + datetime.timedelta(days=1000) + date = date_today() + datetime.timedelta(days=365) + date2 = date_today() + datetime.timedelta(days=1000) PersonFactory(user__username='plain') area = GroupFactory(type_id='area') ad = Person.objects.get(user__username='ad') diff --git a/ietf/meeting/tests_helpers.py b/ietf/meeting/tests_helpers.py index 3160f9388..d77610baa 100644 --- a/ietf/meeting/tests_helpers.py +++ b/ietf/meeting/tests_helpers.py @@ -18,6 +18,7 @@ from ietf.meeting.models import SchedTimeSessAssignment, Session from ietf.meeting.test_data import make_meeting_test_data from ietf.utils.meetecho import Conference from ietf.utils.test_utils import TestCase +from ietf.utils.timezone import date_today # override the legacy office hours setting to guarantee consistency with the tests @@ -623,12 +624,13 @@ class HelperTests(TestCase): def test_get_ietf_meeting(self): """get_ietf_meeting() should only return IETF meetings""" # put the IETF far in the past so it's not "current" - ietf = MeetingFactory(type_id='ietf', date=datetime.date.today() - datetime.timedelta(days=5 * 365)) + today = date_today() + ietf = MeetingFactory(type_id='ietf', date=today- datetime.timedelta(days=5 * 365)) # put the interim meeting now so it will be picked up as "current" if there's a bug - interim = MeetingFactory(type_id='interim', date=datetime.date.today()) + interim = MeetingFactory(type_id='interim', date=today) self.assertEqual(get_ietf_meeting(ietf.number), ietf, 'Return IETF meeting by number') self.assertIsNone(get_ietf_meeting(interim.number), 'Ignore non-IETF meetings') self.assertIsNone(get_ietf_meeting(), 'Return None if there is no current IETF meeting') - ietf.date = datetime.date.today() + ietf.date = today ietf.save() self.assertEqual(get_ietf_meeting(), ietf, 'Return current meeting if there is one') diff --git a/ietf/meeting/tests_js.py b/ietf/meeting/tests_js.py index 015f6d7eb..d93835ac6 100644 --- a/ietf/meeting/tests_js.py +++ b/ietf/meeting/tests_js.py @@ -831,7 +831,7 @@ class EditMeetingScheduleTests(IetfSeleniumTestCase): To test for recurrence of https://trac.ietf.org/trac/ietfdb/ticket/3327 need to have some constraints that do not conflict. Testing with only violated constraints does not exercise the code adequately. """ - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today(), populate_schedule=False) + meeting = MeetingFactory(type_id='ietf', date=date_today(), populate_schedule=False) TimeSlotFactory.create_batch(5, meeting=meeting) schedule = ScheduleFactory(meeting=meeting) sessions = SessionFactory.create_batch(5, meeting=meeting, add_to_schedule=False) @@ -953,7 +953,7 @@ class InterimTests(IetfSeleniumTestCase): # Create a group with a plenary interim session for testing type filters somegroup = GroupFactory(acronym='sg', name='Some Group') - sg_interim = make_interim_meeting(somegroup, datetime.date.today() + datetime.timedelta(days=20)) + sg_interim = make_interim_meeting(somegroup, date_today() + datetime.timedelta(days=20)) sg_sess = sg_interim.session_set.first() sg_slot = sg_sess.timeslotassignments.first().timeslot sg_sess.purpose_id = 'plenary' @@ -1444,7 +1444,7 @@ class ProceedingsMaterialTests(IetfSeleniumTestCase): def setUp(self): super().setUp() self.wait = WebDriverWait(self.driver, 2) - self.meeting = MeetingFactory(type_id='ietf', number='123', date=datetime.date.today()) + self.meeting = MeetingFactory(type_id='ietf', number='123', date=date_today()) def test_add_proceedings_material(self): url = self.absreverse( diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py index bda6c84bc..c8f209bdc 100644 --- a/ietf/meeting/tests_views.py +++ b/ietf/meeting/tests_views.py @@ -901,7 +901,7 @@ class EditMeetingScheduleTests(TestCase): # Meeting must be in the future so it can be edited meeting = MeetingFactory( type_id='ietf', - date=datetime.date.today() + datetime.timedelta(days=7), + date=date_today() + datetime.timedelta(days=7), populate_schedule=False, ) meeting.schedule = ScheduleFactory(meeting=meeting) @@ -1556,7 +1556,7 @@ class EditMeetingScheduleTests(TestCase): """Schedule editor should not crash when there are no timeslots""" meeting = MeetingFactory( type_id='ietf', - date=datetime.date.today() + datetime.timedelta(days=7), + date=date_today() + datetime.timedelta(days=7), populate_schedule=False, ) meeting.schedule = ScheduleFactory(meeting=meeting) @@ -2673,7 +2673,7 @@ class ReorderSlidesTests(TestCase): def test_add_slides_to_session(self): for type_id in ('ietf','interim'): chair_role = RoleFactory(name_id='chair') - session = SessionFactory(group=chair_role.group, meeting__date=datetime.date.today()-datetime.timedelta(days=90), meeting__type_id=type_id) + session = SessionFactory(group=chair_role.group, meeting__date=date_today() - datetime.timedelta(days=90), meeting__type_id=type_id) slides = DocumentFactory(type_id='slides') url = urlreverse('ietf.meeting.views.ajax_add_slides_to_session', kwargs={'session_id':session.pk, 'num':session.meeting.number}) @@ -2689,7 +2689,7 @@ class ReorderSlidesTests(TestCase): self.assertEqual(r.status_code, 403) self.assertIn('materials cutoff', unicontent(r)) - session.meeting.date = datetime.date.today() + session.meeting.date = date_today() session.meeting.save() # Invalid order @@ -2776,7 +2776,7 @@ class ReorderSlidesTests(TestCase): def test_remove_slides_from_session(self): for type_id in ['ietf','interim']: chair_role = RoleFactory(name_id='chair') - session = SessionFactory(group=chair_role.group, meeting__date=datetime.date.today()-datetime.timedelta(days=90), meeting__type_id=type_id) + session = SessionFactory(group=chair_role.group, meeting__date=date_today()-datetime.timedelta(days=90), meeting__type_id=type_id) slides = DocumentFactory(type_id='slides') url = urlreverse('ietf.meeting.views.ajax_remove_slides_from_session', kwargs={'session_id':session.pk, 'num':session.meeting.number}) @@ -2792,7 +2792,7 @@ class ReorderSlidesTests(TestCase): self.assertEqual(r.status_code, 403) self.assertIn('materials cutoff', unicontent(r)) - session.meeting.date = datetime.date.today() + session.meeting.date = date_today() session.meeting.save() # Invalid order @@ -2887,7 +2887,7 @@ class ReorderSlidesTests(TestCase): def test_reorder_slides_in_session(self): chair_role = RoleFactory(name_id='chair') - session = SessionFactory(group=chair_role.group, meeting__date=datetime.date.today()-datetime.timedelta(days=90)) + session = SessionFactory(group=chair_role.group, meeting__date=date_today() - datetime.timedelta(days=90)) sp_list = SessionPresentationFactory.create_batch(5, document__type_id='slides', session=session) for num, sp in enumerate(sp_list, start=1): sp.order = num @@ -2897,7 +2897,7 @@ class ReorderSlidesTests(TestCase): for type_id in ['ietf','interim']: session.meeting.type_id = type_id - session.meeting.date = datetime.date.today()-datetime.timedelta(days=90) + session.meeting.date = date_today()-datetime.timedelta(days=90) session.meeting.save() # Not a valid user @@ -2912,7 +2912,7 @@ class ReorderSlidesTests(TestCase): self.assertEqual(r.status_code, 403) self.assertIn('materials cutoff', unicontent(r)) - session.meeting.date = datetime.date.today() + session.meeting.date = date_today() session.meeting.save() # Bad index values @@ -2979,7 +2979,7 @@ class ReorderSlidesTests(TestCase): def test_slide_order_reconditioning(self): chair_role = RoleFactory(name_id='chair') - session = SessionFactory(group=chair_role.group, meeting__date=datetime.date.today()-datetime.timedelta(days=90)) + session = SessionFactory(group=chair_role.group, meeting__date=date_today() - datetime.timedelta(days=90)) sp_list = SessionPresentationFactory.create_batch(5, document__type_id='slides', session=session) for num, sp in enumerate(sp_list, start=1): sp.order = 2*num @@ -2998,7 +2998,7 @@ class EditTests(TestCase): def test_official_record_schedule_is_read_only(self): def _set_date_offset_and_retrieve_page(meeting, days_offset, client): - meeting.date = datetime.date.today() + datetime.timedelta(days=days_offset) + meeting.date = date_today() + datetime.timedelta(days=days_offset) meeting.save() client.login(username="secretary", password="secretary+password") url = urlreverse("ietf.meeting.views.edit_meeting_schedule", kwargs=dict(num=meeting.number)) @@ -3802,7 +3802,7 @@ class SessionDetailsTests(TestCase): def test_session_details(self): group = GroupFactory.create(type_id='wg',state_id='active') - session = SessionFactory.create(meeting__type_id='ietf',group=group, meeting__date=datetime.date.today()+datetime.timedelta(days=90)) + session = SessionFactory.create(meeting__type_id='ietf',group=group, meeting__date=date_today() + datetime.timedelta(days=90)) SessionPresentationFactory.create(session=session,document__type_id='draft',rev=None) SessionPresentationFactory.create(session=session,document__type_id='minutes') SessionPresentationFactory.create(session=session,document__type_id='slides') @@ -3821,7 +3821,7 @@ class SessionDetailsTests(TestCase): session = SessionFactory.create( meeting__type_id='ietf', group=group, - meeting__date=datetime.date.today() + datetime.timedelta(days=90), + meeting__date=date_today() + datetime.timedelta(days=90), ) session_details_url = urlreverse( 'ietf.meeting.views.session_details', @@ -3873,7 +3873,7 @@ class SessionDetailsTests(TestCase): def test_session_details_past_interim(self): group = GroupFactory.create(type_id='wg',state_id='active') chair = RoleFactory(name_id='chair',group=group) - session = SessionFactory.create(meeting__type_id='interim',group=group, meeting__date=datetime.date.today()-datetime.timedelta(days=90)) + session = SessionFactory.create(meeting__type_id='interim',group=group, meeting__date=date_today() - datetime.timedelta(days=90)) SessionPresentationFactory.create(session=session,document__type_id='draft',rev=None) SessionPresentationFactory.create(session=session,document__type_id='minutes') SessionPresentationFactory.create(session=session,document__type_id='slides') @@ -3892,7 +3892,7 @@ class SessionDetailsTests(TestCase): group = GroupFactory.create(type_id='wg',state_id='active') group_chair = PersonFactory.create() group.role_set.create(name_id='chair',person = group_chair, email = group_chair.email()) - session = SessionFactory.create(meeting__type_id='ietf',group=group, meeting__date=datetime.date.today()+datetime.timedelta(days=90)) + session = SessionFactory.create(meeting__type_id='ietf',group=group, meeting__date=date_today() + datetime.timedelta(days=90)) SessionPresentationFactory.create(session=session,document__type_id='draft',rev=None) old_draft = session.sessionpresentation_set.filter(document__type='draft').first().document new_draft = DocumentFactory(type_id='draft') @@ -4058,7 +4058,7 @@ class InterimTests(TestCase): def do_interim_skip_announcement_test(self, base_session=False, extra_session=False, canceled_session=False): make_meeting_test_data() group = Group.objects.get(acronym='irg') - date = datetime.date.today() + datetime.timedelta(days=30) + date = date_today() + datetime.timedelta(days=30) meeting = make_interim_meeting(group=group, date=date, status='scheda') session = meeting.session_set.first() if base_session: @@ -4337,7 +4337,7 @@ class InterimTests(TestCase): self.do_interim_approve_by_secretariat_test(extra_session=True, canceled_session=True, base_session=True) def test_past(self): - today = datetime.date.today() + today = date_today() last_week = today - datetime.timedelta(days=7) ietf = SessionFactory(meeting__type_id='ietf',meeting__date=last_week,group__state_id='active',group__parent=GroupFactory(state_id='active')) SessionFactory(meeting__type_id='interim',meeting__date=last_week,status_id='canceled',group__state_id='active',group__parent=GroupFactory(state_id='active')) @@ -4356,7 +4356,7 @@ class InterimTests(TestCase): if querystring is not None: url += '?' + querystring - today = datetime.date.today() + today = date_today() interims = dict( mars=add_event_info_to_session_qs(Session.objects.filter(meeting__type='interim', meeting__date__gt=today, group__acronym='mars')).filter(current_status='sched').first().meeting, ames=add_event_info_to_session_qs(Session.objects.filter(meeting__type='interim', meeting__date__gt=today, group__acronym='ames')).filter(current_status='canceled').first().meeting, @@ -4662,7 +4662,7 @@ class InterimTests(TestCase): def test_interim_request_multi_day_non_consecutive(self): make_meeting_test_data() - date = datetime.date.today() + datetime.timedelta(days=30) + date = date_today() + datetime.timedelta(days=30) date2 = date + datetime.timedelta(days=2) time = timezone.now().time().replace(microsecond=0,second=0) group = Group.objects.get(acronym='mars') @@ -4699,7 +4699,7 @@ class InterimTests(TestCase): def test_interim_request_multi_day_cancel(self): """All sessions of a multi-day interim request should be canceled""" length_before = len(outbox) - date = datetime.date.today()+datetime.timedelta(days=15) + date = date_today() + datetime.timedelta(days=15) # Set up an interim request with several sessions num_sessions = 3 @@ -4897,7 +4897,7 @@ class InterimTests(TestCase): def test_interim_request_details_announcement(self): '''Test access to Announce / Skip Announce features''' make_meeting_test_data() - date = datetime.date.today() + datetime.timedelta(days=30) + date = date_today() + datetime.timedelta(days=30) group = Group.objects.get(acronym='mars') meeting = make_interim_meeting(group=group, date=date, status='scheda') url = urlreverse('ietf.meeting.views.interim_request_details',kwargs={'number':meeting.number}) @@ -5636,7 +5636,7 @@ class MaterialsTests(TestCase): def test_upload_bluesheets_interim_chair_access(self): make_meeting_test_data() mars = Group.objects.get(acronym='mars') - session=SessionFactory(meeting__type_id='interim',group=mars, meeting__date = datetime.date.today()) + session=SessionFactory(meeting__type_id='interim',group=mars, meeting__date = date_today()) url = urlreverse('ietf.meeting.views.upload_session_bluesheets',kwargs={'num':session.meeting.number,'session_id':session.id}) self.client.login(username="marschairman", password="marschairman+password") r = self.client.get(url) @@ -5879,7 +5879,7 @@ class MaterialsTests(TestCase): for type_id in ['ietf','interim']: session = SessionFactory(meeting__type_id=type_id) chair = RoleFactory(group=session.group,name_id='chair').person - session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20)) + session.meeting.importantdate_set.create(name_id='revsub',date=date_today() + datetime.timedelta(days=20)) newperson = PersonFactory() session_overview_url = urlreverse('ietf.meeting.views.session_details',kwargs={'num':session.meeting.number,'acronym':session.group.acronym}) @@ -5927,7 +5927,7 @@ class MaterialsTests(TestCase): def test_disapprove_proposed_slides(self): submission = SlideSubmissionFactory() - submission.session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20)) + submission.session.meeting.importantdate_set.create(name_id='revsub',date=date_today() + datetime.timedelta(days=20)) self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(), 1) chair = RoleFactory(group=submission.session.group,name_id='chair').person url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number}) @@ -5945,7 +5945,7 @@ class MaterialsTests(TestCase): def test_approve_proposed_slides(self): submission = SlideSubmissionFactory() session = submission.session - session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20)) + session.meeting.importantdate_set.create(name_id='revsub',date=date_today() + datetime.timedelta(days=20)) chair = RoleFactory(group=submission.session.group,name_id='chair').person url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number}) login_testing_unauthorized(self, chair.user.username, url) @@ -5970,7 +5970,7 @@ class MaterialsTests(TestCase): submission = SlideSubmissionFactory(session__meeting__type_id='ietf') session1 = submission.session session2 = SessionFactory(group=submission.session.group, meeting=submission.session.meeting) - submission.session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20)) + submission.session.meeting.importantdate_set.create(name_id='revsub',date=date_today() + datetime.timedelta(days=20)) chair = RoleFactory(group=submission.session.group,name_id='chair').person url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number}) login_testing_unauthorized(self, chair.user.username, url) @@ -5987,7 +5987,7 @@ class MaterialsTests(TestCase): submission = SlideSubmissionFactory(session__meeting__type_id='ietf') session1 = submission.session session2 = SessionFactory(group=submission.session.group, meeting=submission.session.meeting) - submission.session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20)) + submission.session.meeting.importantdate_set.create(name_id='revsub',date=date_today() + datetime.timedelta(days=20)) chair = RoleFactory(group=submission.session.group,name_id='chair').person url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number}) login_testing_unauthorized(self, chair.user.username, url) @@ -6001,7 +6001,7 @@ class MaterialsTests(TestCase): def test_submit_and_approve_multiple_versions(self): session = SessionFactory(meeting__type_id='ietf') chair = RoleFactory(group=session.group,name_id='chair').person - session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20)) + session.meeting.importantdate_set.create(name_id='revsub',date=date_today()+datetime.timedelta(days=20)) newperson = PersonFactory() propose_url = urlreverse('ietf.meeting.views.propose_session_slides', kwargs={'session_id':session.pk, 'num': session.meeting.number}) @@ -6382,8 +6382,8 @@ class HasMeetingsTests(TestCase): self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertTrue(q('#id_group option[value="%d"]'%group.pk)) - date = datetime.date.today() + datetime.timedelta(days=30+meeting_count) - time = timezone.now().time().replace(microsecond=0,second=0) + date = date_today() + datetime.timedelta(days=30+meeting_count) + time = time_now().replace(microsecond=0,second=0) remote_instructions = 'Use webex' agenda = 'Intro. Slides. Discuss.' agenda_note = 'On second level' diff --git a/ietf/meeting/utils.py b/ietf/meeting/utils.py index 5d9c9aee1..e8efb92ad 100644 --- a/ietf/meeting/utils.py +++ b/ietf/meeting/utils.py @@ -28,6 +28,7 @@ from ietf.person.models import Person from ietf.secr.proceedings.proc_utils import import_audio_files from ietf.utils.html import sanitize_document from ietf.utils.log import log +from ietf.utils.timezone import date_today def session_time_for_sorting(session, use_meeting_date): @@ -70,12 +71,12 @@ def group_sessions(sessions): sessions = sorted(sessions,key=lambda s:s.time) - today = datetime.date.today() future = [] in_progress = [] recent = [] past = [] for s in sessions: + today = date_today(s.meeting.tz()) if s.meeting.date > today: future.append(s) elif s.meeting.end_date() >= today: @@ -107,7 +108,7 @@ def get_upcoming_manageable_sessions(user): # .filter(date__gte=today - F('days')), but unfortunately, it # doesn't work correctly with Django 1.11 and MySQL/SQLite - today = datetime.date.today() + today = date_today() candidate_sessions = add_event_info_to_session_qs( Session.objects.filter(meeting__date__gte=today - datetime.timedelta(days=15)) diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 0651c6877..c9e22cdf1 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -3589,7 +3589,7 @@ def upcoming_ical(request): def upcoming_json(request): '''Return Upcoming meetings in json format''' - today = datetime_today() + today = date_today() # get meetings starting 7 days ago -- we'll filter out sessions in the past further down meetings = data_for_meetings_overview(Meeting.objects.filter(date__gte=today-datetime.timedelta(days=7)).order_by('date')) @@ -3997,7 +3997,7 @@ def important_dates(request, num=None, output_format=None): base_num = int(meeting.number) user = request.user - today = datetime_today() + today = date_today() meetings = [] if meeting.show_important_dates or meeting.date < today: meetings.append(meeting) diff --git a/ietf/message/tests.py b/ietf/message/tests.py index c1f22b3d0..a027df447 100644 --- a/ietf/message/tests.py +++ b/ietf/message/tests.py @@ -15,10 +15,13 @@ from ietf.message.utils import send_scheduled_message_from_send_queue from ietf.person.models import Person from ietf.utils.mail import outbox, send_mail_text, send_mail_message, get_payload_text from ietf.utils.test_utils import TestCase +from ietf.utils.timezone import date_today + + class MessageTests(TestCase): def test_message_view(self): - nomcom = GroupFactory(name="nomcom%s" % datetime.date.today().year, type_id="nomcom") + nomcom = GroupFactory(name="nomcom%s" % date_today().year, type_id="nomcom") msg = Message.objects.create( by=Person.objects.get(name="(System)"), subject="This is a test", diff --git a/ietf/nomcom/management/commands/send_reminders.py b/ietf/nomcom/management/commands/send_reminders.py index 3dce0a361..bc1042543 100644 --- a/ietf/nomcom/management/commands/send_reminders.py +++ b/ietf/nomcom/management/commands/send_reminders.py @@ -2,13 +2,14 @@ # -*- coding: utf-8 -*- -import datetime import syslog from django.core.management.base import BaseCommand from ietf.nomcom.models import NomCom, NomineePosition from ietf.nomcom.utils import send_accept_reminder_to_nominee,send_questionnaire_reminder_to_nominee +from ietf.utils.timezone import date_today + def log(message): syslog.syslog(message) @@ -27,10 +28,10 @@ class Command(BaseCommand): for nomcom in NomCom.objects.filter(group__state__slug='active'): nps = NomineePosition.objects.filter(nominee__nomcom=nomcom,nominee__duplicated__isnull=True) for nominee_position in nps.pending(): - if is_time_to_send(nomcom, datetime.date.today(), nominee_position.time.date()): + if is_time_to_send(nomcom, date_today(), nominee_position.time.date()): send_accept_reminder_to_nominee(nominee_position) log('Sent accept reminder to %s' % nominee_position.nominee.email.address) for nominee_position in nps.accepted().without_questionnaire_response(): - if is_time_to_send(nomcom, datetime.date.today(), nominee_position.time.date()): + if is_time_to_send(nomcom, date_today(), nominee_position.time.date()): send_questionnaire_reminder_to_nominee(nominee_position) log('Sent questionnaire reminder to %s' % nominee_position.nominee.email.address) diff --git a/ietf/nomcom/tests.py b/ietf/nomcom/tests.py index 6bd9ff2bb..0577ca558 100644 --- a/ietf/nomcom/tests.py +++ b/ietf/nomcom/tests.py @@ -50,7 +50,7 @@ from ietf.stats.models import MeetingRegistration from ietf.stats.factories import MeetingRegistrationFactory from ietf.utils.mail import outbox, empty_outbox, get_payload_text from ietf.utils.test_utils import login_testing_unauthorized, TestCase, unicontent -from ietf.utils.timezone import datetime_today, datetime_from_date, DEADLINE_TZINFO +from ietf.utils.timezone import date_today, datetime_today, datetime_from_date, DEADLINE_TZINFO client_test_cert_files = None @@ -1130,7 +1130,7 @@ class ReminderTest(TestCase): def test_is_time_to_send(self): self.nomcom.reminder_interval = 4 - today = datetime.date.today() + today = date_today() self.assertTrue(is_time_to_send(self.nomcom,today+datetime.timedelta(days=4),today)) for delta in range(4): self.assertFalse(is_time_to_send(self.nomcom,today+datetime.timedelta(days=delta),today)) @@ -1236,7 +1236,7 @@ class InactiveNomcomTests(TestCase): self.assertIn( 'closed', q('.alert-warning').text()) def test_acceptance_closed(self): - today = datetime.date.today().strftime('%Y%m%d') + today = date_today().strftime('%Y%m%d') pid = self.nc.position_set.first().nomineeposition_set.order_by('pk').first().id url = reverse('ietf.nomcom.views.process_nomination_status', kwargs = { 'year' : self.nc.year(), @@ -1892,7 +1892,7 @@ Junk body for testing assert year >= 1990 return (year-1985)*3+2 # Create meetings to ensure we have the 'last 5' - meeting_start = first_meeting_of_year(datetime.date.today().year-2) + meeting_start = first_meeting_of_year(date_today().year-2) # Populate the meeting registration records for number in range(meeting_start, meeting_start+10): meeting = MeetingFactory.create(type_id='ietf', number=number) @@ -2244,7 +2244,8 @@ class EligibilityUnitTests(TestCase): def test_get_eligibility_date(self): # No Nomcoms exist: - self.assertEqual(get_eligibility_date(), datetime.date(datetime.date.today().year,5,1)) + this_year = date_today().year + self.assertEqual(get_eligibility_date(), datetime.date(this_year,5,1)) # a provided date trumps anything in the database self.assertEqual(get_eligibility_date(date=datetime.date(2001,2,3)), datetime.date(2001,2,3)) @@ -2258,7 +2259,7 @@ class EligibilityUnitTests(TestCase): n.save() self.assertEqual(get_eligibility_date(nomcom=n), datetime.date(2015,5,17)) # No nomcoms in the database with seated members - self.assertEqual(get_eligibility_date(), datetime.date(datetime.date.today().year,5,1)) + self.assertEqual(get_eligibility_date(), datetime.date(this_year,5,1)) RoleFactory(group=n.group,name_id='member') self.assertEqual(get_eligibility_date(),datetime.date(2016,5,1)) @@ -2266,7 +2267,6 @@ class EligibilityUnitTests(TestCase): NomComFactory(group__acronym='nomcom2016', populate_personnel=False, first_call_for_volunteers=datetime.date(2016,5,4)) self.assertEqual(get_eligibility_date(),datetime.date(2016,5,4)) - this_year = datetime.date.today().year NomComFactory(group__acronym=f'nomcom{this_year}', first_call_for_volunteers=datetime.date(this_year,5,6)) self.assertEqual(get_eligibility_date(),datetime.date(this_year,5,6)) @@ -2636,8 +2636,8 @@ class VolunteerTests(TestCase): r = self.client.get(url) self.assertContains(r, 'NomCom is not accepting volunteers at this time', status_code=200) - year = datetime.date.today().year - nomcom = NomComFactory(group__acronym=f'nomcom{year}', is_accepting_volunteers=False) + this_year = date_today().year + nomcom = NomComFactory(group__acronym=f'nomcom{this_year}', is_accepting_volunteers=False) r = self.client.get(url) self.assertContains(r, 'NomCom is not accepting volunteers at this time', status_code=200) nomcom.is_accepting_volunteers = True @@ -2660,7 +2660,7 @@ class VolunteerTests(TestCase): self.assertContains(r, 'already volunteered', status_code=200) person.volunteer_set.all().delete() - nomcom2 = NomComFactory(group__acronym=f'nomcom{year-1}', is_accepting_volunteers=True) + nomcom2 = NomComFactory(group__acronym=f'nomcom{this_year-1}', is_accepting_volunteers=True) r = self.client.get(url) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) diff --git a/ietf/nomcom/utils.py b/ietf/nomcom/utils.py index a99ce1303..50712f9aa 100644 --- a/ietf/nomcom/utils.py +++ b/ietf/nomcom/utils.py @@ -34,7 +34,7 @@ from ietf.utils.pipe import pipe from ietf.utils.mail import send_mail_text, send_mail, get_payload_text from ietf.utils.log import log from ietf.person.name import unidecode_name -from ietf.utils.timezone import datetime_from_date, datetime_today, DEADLINE_TZINFO +from ietf.utils.timezone import date_today, datetime_from_date, DEADLINE_TZINFO import debug # pyflakes:ignore @@ -241,7 +241,7 @@ def validate_public_key(public_key): def send_accept_reminder_to_nominee(nominee_position): - today = datetime.date.today().strftime('%Y%m%d') + today = date_today().strftime('%Y%m%d') subject = 'Reminder: please accept (or decline) your nomination.' domain = Site.objects.get_current().domain position = nominee_position.position @@ -333,7 +333,7 @@ def make_nomineeposition(nomcom, candidate, position, author): from_email = settings.NOMCOM_FROM_EMAIL.format(year=nomcom.year()) (to_email, cc) = gather_address_lists('nomination_new_nominee',nominee=nominee.email.address) domain = Site.objects.get_current().domain - today = datetime.date.today().strftime('%Y%m%d') + today = date_today().strftime('%Y%m%d') hash = get_hash_nominee_position(today, nominee_position.id) accept_url = reverse('ietf.nomcom.views.process_nomination_status', None, @@ -626,7 +626,7 @@ def get_eligibility_date(nomcom=None, date=None): last_seated=Role.objects.filter(group__type_id='nomcom',name_id='member').order_by('-group__acronym').first() if last_seated: last_nomcom_year = int(last_seated.group.acronym[6:]) - if last_nomcom_year == datetime.date.today().year: + if last_nomcom_year == date_today().year: next_nomcom_year = last_nomcom_year else: next_nomcom_year = int(last_seated.group.acronym[6:])+1 @@ -636,11 +636,11 @@ def get_eligibility_date(nomcom=None, date=None): else: return datetime.date(next_nomcom_year,5,1) else: - return datetime.date(datetime_today().year,5,1) + return datetime.date(date_today().year,5,1) def previous_five_meetings(date = None): if date is None: - date = datetime.date.today() + date = date_today() return Meeting.objects.filter(type='ietf',date__lte=date).order_by('-date')[:5] def three_of_five_eligible_8713(previous_five, queryset=None): diff --git a/ietf/nomcom/views.py b/ietf/nomcom/views.py index cbdd6eba9..6f02b16e2 100644 --- a/ietf/nomcom/views.py +++ b/ietf/nomcom/views.py @@ -45,6 +45,8 @@ from ietf.nomcom.utils import (get_nomcom_by_year, store_nomcom_private_key, sug from ietf.ietfauth.utils import role_required from ietf.person.models import Person from ietf.utils.response import permission_denied +from ietf.utils.timezone import date_today + import debug # pyflakes:ignore @@ -702,7 +704,7 @@ def process_nomination_status(request, year, nominee_position_id, state, date, h expiration_days = getattr(settings, 'DAYS_TO_EXPIRE_NOMINATION_LINK', None) if expiration_days: request_date = datetime.date(int(date[:4]), int(date[4:6]), int(date[6:])) - if datetime.date.today() > (request_date + datetime.timedelta(days=settings.DAYS_TO_EXPIRE_NOMINATION_LINK)): + if date_today() > (request_date + datetime.timedelta(days=expiration_days)): permission_denied(request, "Link expired.") need_confirmation = True diff --git a/ietf/person/templatetags/person_filters.py b/ietf/person/templatetags/person_filters.py index 96696456f..017b29c63 100644 --- a/ietf/person/templatetags/person_filters.py +++ b/ietf/person/templatetags/person_filters.py @@ -1,13 +1,12 @@ # Copyright The IETF Trust 2017-2020, All Rights Reserved -import datetime - from django import template import debug # pyflakes:ignore from ietf.nomcom.utils import is_eligible from ietf.person.models import Alias +from ietf.utils.timezone import date_today register = template.Library() @@ -15,7 +14,7 @@ register = template.Library() @register.filter def is_nomcom_eligible(person, date=None): if date is None: - date = datetime.date.today() + date = date_today() return is_eligible(person=person, date=date) diff --git a/ietf/person/views.py b/ietf/person/views.py index fca943e2d..59ab9366c 100644 --- a/ietf/person/views.py +++ b/ietf/person/views.py @@ -2,7 +2,6 @@ # -*- coding: utf-8 -*- -import datetime from io import StringIO, BytesIO from PIL import Image @@ -10,6 +9,7 @@ from django.contrib import messages from django.db.models import Q from django.http import HttpResponse, Http404 from django.shortcuts import render, get_object_or_404, redirect +from django.utils import timezone import debug # pyflakes:ignore @@ -76,7 +76,7 @@ def profile(request, email_or_name): persons = [ p for p in persons if p and p.id ] if not persons: raise Http404 - return render(request, 'person/profile.html', {'persons': persons, 'today':datetime.date.today()}) + return render(request, 'person/profile.html', {'persons': persons, 'today': timezone.now()}) def photo(request, email_or_name): diff --git a/ietf/review/mailarch.py b/ietf/review/mailarch.py index 2ca6c9566..6ef5909a1 100644 --- a/ietf/review/mailarch.py +++ b/ietf/review/mailarch.py @@ -25,6 +25,8 @@ from django.conf import settings from django.utils.encoding import force_bytes, force_str from ietf.utils.mail import get_payload_text +from ietf.utils.timezone import date_today + def list_name_from_email(list_email): if not list_email.endswith("@ietf.org"): @@ -51,7 +53,7 @@ def construct_query_urls(doc, team, query=None): encoded_query = "?" + urlencode({ "qdr": "c", # custom time frame - "start_date": (datetime.date.today() - datetime.timedelta(days=180)).isoformat(), + "start_date": (date_today() - datetime.timedelta(days=180)).isoformat(), "email_list": list_name, "q": "subject:({})".format(query), "as": "1", # this is an advanced search @@ -89,7 +91,7 @@ def retrieve_messages_from_mbox(mbox_fileobj): utcdate = None d = email.utils.parsedate_tz(msg["Date"]) if d: - utcdate = datetime.datetime.fromtimestamp(email.utils.mktime_tz(d)) + utcdate = datetime.datetime.fromtimestamp(email.utils.mktime_tz(d), datetime.timezone.utc) res.append({ "from": msg["From"], diff --git a/ietf/review/migrations/0030_use_date_today_helper.py b/ietf/review/migrations/0030_use_date_today_helper.py new file mode 100644 index 000000000..b006d276f --- /dev/null +++ b/ietf/review/migrations/0030_use_date_today_helper.py @@ -0,0 +1,24 @@ +# Generated by Django 2.2.28 on 2022-10-18 15:43 + +from django.db import migrations, models +import ietf.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('review', '0029_use_timezone_now_for_review_models'), + ] + + operations = [ + migrations.AlterField( + model_name='historicalunavailableperiod', + name='start_date', + field=models.DateField(default=ietf.utils.timezone.date_today, help_text="Choose the start date so that you can still do a review if it's assigned just before the start date - this usually means you should mark yourself unavailable for assignment some time before you are actually away. The default is today.", null=True), + ), + migrations.AlterField( + model_name='unavailableperiod', + name='start_date', + field=models.DateField(default=ietf.utils.timezone.date_today, help_text="Choose the start date so that you can still do a review if it's assigned just before the start date - this usually means you should mark yourself unavailable for assignment some time before you are actually away. The default is today.", null=True), + ), + ] diff --git a/ietf/review/models.py b/ietf/review/models.py index 0ec367819..f0ec78094 100644 --- a/ietf/review/models.py +++ b/ietf/review/models.py @@ -2,8 +2,6 @@ # -*- coding: utf-8 -*- -import datetime - from simple_history.models import HistoricalRecords from django.db import models @@ -18,6 +16,8 @@ from ietf.name.models import ReviewTypeName, ReviewRequestStateName, ReviewResul ReviewAssignmentStateName, ReviewerQueuePolicyName from ietf.utils.validators import validate_regular_expression_string from ietf.utils.models import ForeignKey, OneToOneField +from ietf.utils.timezone import date_today + class ReviewerSettings(models.Model): """Keeps track of admin data associated with a reviewer in a team.""" @@ -67,7 +67,7 @@ class UnavailablePeriod(models.Model): history = HistoricalRecords(history_change_reason_field=models.TextField(null=True)) team = ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) person = ForeignKey(Person) - start_date = models.DateField(default=datetime.date.today, null=True, help_text="Choose the start date so that you can still do a review if it's assigned just before the start date - this usually means you should mark yourself unavailable for assignment some time before you are actually away. The default is today.") + start_date = models.DateField(default=date_today, null=True, help_text="Choose the start date so that you can still do a review if it's assigned just before the start date - this usually means you should mark yourself unavailable for assignment some time before you are actually away. The default is today.") end_date = models.DateField(blank=True, null=True, help_text="Leaving the end date blank means that the period continues indefinitely. You can end it later.") AVAILABILITY_CHOICES = [ ("canfinish", "Can do follow-ups"), @@ -81,8 +81,7 @@ class UnavailablePeriod(models.Model): reason = models.TextField(verbose_name="Reason why reviewer is unavailable (Optional)", max_length=2048, blank=True, help_text="Provide (for the secretary's benefit) the reason why the review is unavailable", default='') def state(self): - import datetime - today = datetime.date.today() + today = date_today() if self.start_date is None or self.start_date <= today: if not self.end_date or today <= self.end_date: return "active" diff --git a/ietf/review/tests.py b/ietf/review/tests.py index 260a8646d..43294801e 100644 --- a/ietf/review/tests.py +++ b/ietf/review/tests.py @@ -5,7 +5,7 @@ import datetime from ietf.group.factories import RoleFactory from ietf.utils.mail import empty_outbox, get_payload_text, outbox from ietf.utils.test_utils import TestCase, reload_db_objects -from ietf.utils.timezone import datetime_from_date +from ietf.utils.timezone import date_today, datetime_from_date from .factories import ReviewAssignmentFactory, ReviewRequestFactory, ReviewerSettingsFactory from .mailarch import hash_list_message_id from .models import ReviewerSettings, ReviewSecretarySettings, ReviewTeamSettings, UnavailablePeriod @@ -75,7 +75,7 @@ class ReviewAssignmentTest(TestCase): class ReviewAssignmentReminderTests(TestCase): - today = datetime.date.today() + today = date_today() deadline = today + datetime.timedelta(days=6) def setUp(self): @@ -346,7 +346,7 @@ class ReviewAssignmentReminderTests(TestCase): def test_send_unavailability_period_ending_reminder(self): secretary = self.make_secretary(username='reviewsecretary') empty_outbox() - today = datetime.date.today() + today = date_today() UnavailablePeriod.objects.create( team=self.team, person=self.reviewer, @@ -470,7 +470,7 @@ class ReviewAssignmentReminderTests(TestCase): self.assertIn('1 overdue review', log[0]) def test_send_reminder_all_open_reviews(self): - today = datetime.date.today() + today = date_today() self.make_secretary(username='reviewsecretary') ReviewerSettingsFactory(team=self.team, person=self.reviewer, remind_days_open_reviews=1) diff --git a/ietf/review/utils.py b/ietf/review/utils.py index 59a909a8e..15312dd93 100644 --- a/ietf/review/utils.py +++ b/ietf/review/utils.py @@ -32,7 +32,7 @@ from ietf.review.models import (ReviewRequest, ReviewAssignment, ReviewRequestSt from ietf.utils.mail import send_mail from ietf.doc.utils import extract_complete_replaces_ancestor_mapping_for_docs from ietf.utils import log -from ietf.utils.timezone import datetime_today, DEADLINE_TZINFO +from ietf.utils.timezone import date_today, datetime_today, DEADLINE_TZINFO # The origin date is used to have a single reference date for "every X days". @@ -93,12 +93,12 @@ def no_review_from_teams_on_doc(doc, rev): def unavailable_periods_to_list(past_days=14): return UnavailablePeriod.objects.filter( - Q(end_date=None) | Q(end_date__gte=datetime.date.today() - datetime.timedelta(days=past_days)), + Q(end_date=None) | Q(end_date__gte=date_today() - datetime.timedelta(days=past_days)), ).order_by("start_date") def current_unavailable_periods_for_reviewers(team): """Return dict with currently active unavailable periods for reviewers.""" - today = datetime.date.today() + today = date_today() unavailable_period_qs = UnavailablePeriod.objects.filter( Q(end_date__gte=today) | Q(end_date=None), @@ -877,7 +877,7 @@ def email_reviewer_reminder(assignment): review_request = assignment.review_request team = review_request.team - deadline_days = (review_request.deadline - datetime.date.today()).days + deadline_days = (review_request.deadline - date_today(DEADLINE_TZINFO)).days subject = "Reminder: deadline for review of {} in {} is {}".format(review_request.doc.name, team.acronym, review_request.deadline.isoformat()) @@ -943,7 +943,7 @@ def email_secretary_reminder(assignment, secretary_role): review_request = assignment.review_request team = review_request.team - deadline_days = (review_request.deadline - datetime.date.today()).days + deadline_days = (review_request.deadline - date_today(DEADLINE_TZINFO)).days subject = "Reminder: deadline for review of {} in {} is {}".format(review_request.doc.name, team.acronym, review_request.deadline.isoformat()) diff --git a/ietf/secr/meetings/views.py b/ietf/secr/meetings/views.py index da2ad94bf..bd0c8efa1 100644 --- a/ietf/secr/meetings/views.py +++ b/ietf/secr/meetings/views.py @@ -31,7 +31,7 @@ from ietf.secr.meetings.forms import ( BaseMeetingRoomFormSet, MeetingModelForm, from ietf.secr.sreq.views import get_initial_session from ietf.secr.utils.meeting import get_session, get_timeslot from ietf.mailtrigger.utils import gather_address_lists -from ietf.utils.timezone import make_aware +from ietf.utils.timezone import date_today, make_aware # prep for agenda changes @@ -314,7 +314,7 @@ def blue_sheet_redirect(request): This is the generic blue sheet URL. It gets the next IETF meeting and redirects to the meeting specific URL. ''' - today = datetime.date.today() + today = date_today() qs = Meeting.objects.filter(date__gt=today,type='ietf').order_by('date') if qs: meeting = qs[0] @@ -821,7 +821,7 @@ def times_edit(request, meeting_id, schedule_name, time): parts = [ int(x) for x in time.split(':') ] dtime = make_aware(datetime.datetime(*parts), meeting.tz()) timeslots = TimeSlot.objects.filter(meeting=meeting,time=dtime) - day = (dtime.date() - meeting.date) // datetime.timedelta(days=1) + day = (dtime.date() - meeting.date).days initial = {'day': day, 'time': dtime.strftime('%H:%M'), 'duration': timeslots.first().duration, diff --git a/ietf/secr/proceedings/views.py b/ietf/secr/proceedings/views.py index b08375176..e88a20196 100644 --- a/ietf/secr/proceedings/views.py +++ b/ietf/secr/proceedings/views.py @@ -27,6 +27,7 @@ from ietf.meeting.utils import add_event_info_to_session_qs from ietf.secr.proceedings.forms import RecordingForm, RecordingEditForm from ietf.secr.proceedings.proc_utils import (create_recording) +from ietf.utils.timezone import date_today # ------------------------------------------------- # Globals @@ -154,7 +155,7 @@ def main(request): meetings = Meeting.objects.filter(type='ietf').order_by('-number') else: # select meetings still within the cutoff period - today = datetime.date.today() + today = date_today() meetings = [m for m in Meeting.objects.filter(type='ietf').order_by('-number') if m.get_submission_correction_date()>=today] groups = get_my_groups(request.user) @@ -165,7 +166,7 @@ def main(request): m.group = m.session_set.first().group # we today's date to see if we're past the submissio cutoff - today = datetime.date.today() + today = date_today() return render(request, 'proceedings/main.html',{ 'meetings': meetings, @@ -304,7 +305,7 @@ def select(request, meeting_num): # get the time proceedings were generated path = os.path.join(settings.SECR_PROCEEDINGS_DIR,meeting.number,'index.html') if os.path.exists(path): - last_run = datetime.datetime.fromtimestamp(os.path.getmtime(path)) + last_run = datetime.datetime.fromtimestamp(os.path.getmtime(path), datetime.timezone.utc) else: last_run = None diff --git a/ietf/secr/sreq/tests.py b/ietf/secr/sreq/tests.py index fabbc0807..7f6707b4d 100644 --- a/ietf/secr/sreq/tests.py +++ b/ietf/secr/sreq/tests.py @@ -16,6 +16,8 @@ from ietf.name.models import ConstraintName, TimerangeName from ietf.person.models import Person from ietf.secr.sreq.forms import SessionForm from ietf.utils.mail import outbox, empty_outbox, get_payload_text +from ietf.utils.timezone import date_today + from pyquery import PyQuery @@ -23,7 +25,7 @@ SECR_USER='secretary' class SreqUrlTests(TestCase): def test_urls(self): - MeetingFactory(type_id='ietf',date=datetime.date.today()) + MeetingFactory(type_id='ietf',date=date_today()) self.client.login(username="secretary", password="secretary+password") @@ -39,7 +41,7 @@ class SreqUrlTests(TestCase): class SessionRequestTestCase(TestCase): def test_main(self): - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today()) + meeting = MeetingFactory(type_id='ietf', date=date_today()) SessionFactory.create_batch(2, meeting=meeting, status_id='sched') SessionFactory.create_batch(2, meeting=meeting, status_id='disappr') # An additional unscheduled group comes from make_immutable_base_data @@ -53,7 +55,7 @@ class SessionRequestTestCase(TestCase): self.assertEqual(len(unsched), 11) def test_approve(self): - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today()) + meeting = MeetingFactory(type_id='ietf', date=date_today()) ad = Person.objects.get(user__username='ad') area = RoleFactory(name_id='ad', person=ad, group__type_id='area').group mars = GroupFactory(parent=area, acronym='mars') @@ -66,7 +68,7 @@ class SessionRequestTestCase(TestCase): self.assertEqual(SchedulingEvent.objects.filter(session=session).order_by('-id')[0].status_id, 'appr') def test_cancel(self): - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today()) + meeting = MeetingFactory(type_id='ietf', date=date_today()) ad = Person.objects.get(user__username='ad') area = RoleFactory(name_id='ad', person=ad, group__type_id='area').group session = SessionFactory(meeting=meeting, group__parent=area, group__acronym='mars', status_id='sched') @@ -77,7 +79,7 @@ class SessionRequestTestCase(TestCase): self.assertEqual(SchedulingEvent.objects.filter(session=session).order_by('-id')[0].status_id, 'deleted') def test_edit(self): - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today()) + meeting = MeetingFactory(type_id='ietf', date=date_today()) mars = RoleFactory(name_id='chair', person__user__username='marschairman', group__acronym='mars').group group2 = GroupFactory() group3 = GroupFactory() @@ -242,7 +244,7 @@ class SessionRequestTestCase(TestCase): def test_edit_constraint_bethere(self): - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today()) + meeting = MeetingFactory(type_id='ietf', date=date_today()) mars = RoleFactory(name_id='chair', person__user__username='marschairman', group__acronym='mars').group session = SessionFactory(meeting=meeting, group=mars, status_id='sched') Constraint.objects.create( @@ -309,7 +311,7 @@ class SessionRequestTestCase(TestCase): def test_edit_inactive_conflicts(self): """Inactive conflicts should be displayed and removable""" - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today(), group_conflicts=['chair_conflict']) + meeting = MeetingFactory(type_id='ietf', date=date_today(), group_conflicts=['chair_conflict']) mars = RoleFactory(name_id='chair', person__user__username='marschairman', group__acronym='mars').group session = SessionFactory(meeting=meeting, group=mars, status_id='sched') other_group = GroupFactory() @@ -367,7 +369,7 @@ class SessionRequestTestCase(TestCase): self.assertEqual(len(mars.constraint_source_set.filter(name_id='conflict')), 0) def test_tool_status(self): - MeetingFactory(type_id='ietf', date=datetime.date.today()) + MeetingFactory(type_id='ietf', date=date_today()) url = reverse('ietf.secr.sreq.views.tool_status') self.client.login(username="secretary", password="secretary+password") r = self.client.get(url) @@ -381,7 +383,7 @@ class SessionRequestTestCase(TestCase): Relies on SessionForm representing constraint values with element IDs like id_constraint_<ConstraintName slug> """ - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today()) + meeting = MeetingFactory(type_id='ietf', date=date_today()) RoleFactory(name_id='chair', person__user__username='marschairman', group__acronym='mars') url = reverse('ietf.secr.sreq.views.new', kwargs=dict(acronym='mars')) self.client.login(username="marschairman", password="marschairman+password") @@ -404,7 +406,7 @@ class SessionRequestTestCase(TestCase): def test_edit_req_constraint_types(self): """Editing a request constraint should show the expected constraints""" - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today()) + meeting = MeetingFactory(type_id='ietf', date=date_today()) SessionFactory(group__acronym='mars', status_id='schedw', meeting=meeting, @@ -438,7 +440,7 @@ class SubmitRequestCase(TestCase): MeetingFactory.reset_sequence(0) def test_submit_request(self): - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today()) + meeting = MeetingFactory(type_id='ietf', date=date_today()) ad = Person.objects.get(user__username='ad') area = RoleFactory(name_id='ad', person=ad, group__type_id='area').group group = GroupFactory(parent=area) @@ -506,7 +508,7 @@ class SubmitRequestCase(TestCase): self.assertEqual(list(session.joint_with_groups.all()), [group3, group4]) def test_submit_request_invalid(self): - MeetingFactory(type_id='ietf', date=datetime.date.today()) + MeetingFactory(type_id='ietf', date=date_today()) ad = Person.objects.get(user__username='ad') area = RoleFactory(name_id='ad', person=ad, group__type_id='area').group group = GroupFactory(parent=area) @@ -542,8 +544,8 @@ class SubmitRequestCase(TestCase): self.assertContains(r, 'Must provide data for all sessions') def test_submit_request_check_constraints(self): - m1 = MeetingFactory(type_id='ietf', date=datetime.date.today() - datetime.timedelta(days=100)) - MeetingFactory(type_id='ietf', date=datetime.date.today(), + m1 = MeetingFactory(type_id='ietf', date=date_today() - datetime.timedelta(days=100)) + MeetingFactory(type_id='ietf', date=date_today(), group_conflicts=['chair_conflict', 'conflic2', 'conflic3']) ad = Person.objects.get(user__username='ad') area = RoleFactory(name_id='ad', person=ad, group__type_id='area').group @@ -604,7 +606,7 @@ class SubmitRequestCase(TestCase): self.assertContains(r, "Cannot declare a conflict with the same group") def test_request_notification(self): - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today()) + meeting = MeetingFactory(type_id='ietf', date=date_today()) ad = Person.objects.get(user__username='ad') area = GroupFactory(type_id='area') RoleFactory(name_id='ad', person=ad, group=area) @@ -699,7 +701,7 @@ class SubmitRequestCase(TestCase): self.assertNotIn('The third session requires your approval', notification_payload) def test_request_notification_third_session(self): - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today()) + meeting = MeetingFactory(type_id='ietf', date=date_today()) ad = Person.objects.get(user__username='ad') area = GroupFactory(type_id='area') RoleFactory(name_id='ad', person=ad, group=area) @@ -807,7 +809,7 @@ class SubmitRequestCase(TestCase): class LockAppTestCase(TestCase): def setUp(self): super().setUp() - self.meeting = MeetingFactory(type_id='ietf', date=datetime.date.today(),session_request_lock_message='locked') + self.meeting = MeetingFactory(type_id='ietf', date=date_today(),session_request_lock_message='locked') self.group = GroupFactory(acronym='mars') RoleFactory(name_id='chair', group=self.group, person__user__username='marschairman') SessionFactory(group=self.group,meeting=self.meeting) @@ -853,7 +855,7 @@ class LockAppTestCase(TestCase): class NotMeetingCase(TestCase): def test_not_meeting(self): - MeetingFactory(type_id='ietf',date=datetime.date.today()) + MeetingFactory(type_id='ietf',date=date_today()) group = GroupFactory(acronym='mars') url = reverse('ietf.secr.sreq.views.no_session',kwargs={'acronym':group.acronym}) self.client.login(username="secretary", password="secretary+password") diff --git a/ietf/secr/telechat/tests.py b/ietf/secr/telechat/tests.py index cc989c6fc..e4661b767 100644 --- a/ietf/secr/telechat/tests.py +++ b/ietf/secr/telechat/tests.py @@ -8,14 +8,13 @@ from pyquery import PyQuery import debug # pyflakes:ignore from django.urls import reverse -from django.utils import timezone from ietf.doc.factories import (WgDraftFactory, IndividualRfcFactory, CharterFactory, IndividualDraftFactory, ConflictReviewFactory) from ietf.doc.models import BallotDocEvent, BallotType, BallotPositionDocEvent, State, Document from ietf.doc.utils import update_telechat, create_ballot_if_not_open from ietf.utils.test_utils import TestCase -from ietf.utils.timezone import datetime_today +from ietf.utils.timezone import date_today, datetime_today from ietf.iesg.models import TelechatDate from ietf.person.models import Person from ietf.person.factories import PersonFactory @@ -24,7 +23,7 @@ from ietf.secr.telechat.views import get_next_telechat_date SECR_USER='secretary' def augment_data(): - TelechatDate.objects.create(date=timezone.now()) + TelechatDate.objects.create(date=date_today()) class SecrTelechatTestCase(TestCase): def test_main(self): @@ -140,7 +139,7 @@ class SecrTelechatTestCase(TestCase): self.assertEqual(q("#telechat-positions-table").find("th:contains('No Record')").length,1) def test_bash(self): - today = timezone.now() + today = date_today() TelechatDate.objects.create(date=today) url = reverse('ietf.secr.telechat.views.bash',kwargs={'date':today.strftime('%Y-%m-%d')}) self.client.login(username="secretary", password="secretary+password") diff --git a/ietf/secr/telechat/views.py b/ietf/secr/telechat/views.py index b3f064fa1..4dd4fba4e 100644 --- a/ietf/secr/telechat/views.py +++ b/ietf/secr/telechat/views.py @@ -20,6 +20,8 @@ from ietf.iesg.models import TelechatDate, TelechatAgendaItem, Telechat from ietf.iesg.agenda import agenda_data, get_doc_section from ietf.ietfauth.utils import role_required from ietf.secr.telechat.forms import BallotForm, ChangeStateForm, DateSelectForm, TELECHAT_TAGS +from ietf.utils.timezone import date_today + ''' EXPECTED CHANGES: @@ -80,14 +82,14 @@ def get_last_telechat_date(): This function returns the date of the last telechat Tried TelechatDocEvent.objects.latest but that will return today's telechat ''' - return TelechatDate.objects.filter(date__lt=datetime.date.today()).order_by('-date')[0].date + return TelechatDate.objects.filter(date__lt=date_today()).order_by('-date')[0].date #return '2011-11-01' # uncomment for testing def get_next_telechat_date(): ''' This function returns the date of the next telechat ''' - return TelechatDate.objects.filter(date__gte=datetime.date.today()).order_by('date')[0].date + return TelechatDate.objects.filter(date__gte=date_today()).order_by('date')[0].date def get_section_header(doc, agenda): ''' diff --git a/ietf/stats/tests.py b/ietf/stats/tests.py index 343fd7f00..dae352752 100644 --- a/ietf/stats/tests.py +++ b/ietf/stats/tests.py @@ -30,6 +30,7 @@ from ietf.review.factories import ReviewRequestFactory, ReviewerSettingsFactory, from ietf.stats.models import MeetingRegistration, CountryAlias from ietf.stats.factories import MeetingRegistrationFactory from ietf.stats.utils import get_meeting_registration_data +from ietf.utils.timezone import date_today class StatisticsTests(TestCase): @@ -123,7 +124,7 @@ class StatisticsTests(TestCase): def test_meeting_stats(self): # create some data for the statistics - meeting = MeetingFactory(type_id='ietf', date=datetime.date.today(), number="96") + meeting = MeetingFactory(type_id='ietf', date=date_today(), number="96") MeetingRegistrationFactory(first_name='John', last_name='Smith', country_code='US', email="john.smith@example.us", meeting=meeting, attended=True) CountryAlias.objects.get_or_create(alias="US", country=CountryName.objects.get(slug="US")) p = MeetingRegistrationFactory(first_name='Jaume', last_name='Guillaume', country_code='FR', email="jaume.guillaume@example.fr", meeting=meeting, attended=False).person @@ -199,7 +200,7 @@ class StatisticsTests(TestCase): self.assertTrue(q('.review-stats td:contains("1")')) # check stacked chart - expected_date = datetime.date.today().replace(day=1) + expected_date = date_today().replace(day=1) expected_js_timestamp = calendar.timegm(expected_date.timetuple()) * 1000 url = urlreverse(ietf.stats.views.review_stats, kwargs={ "stats_type": "time" }) url += "?team={}".format(review_req.team.acronym) diff --git a/ietf/stats/views.py b/ietf/stats/views.py index 2df9f95c2..09a25b47b 100644 --- a/ietf/stats/views.py +++ b/ietf/stats/views.py @@ -641,7 +641,7 @@ def document_stats(request, stats_type=None): template_name = "yearly" years_from = from_time.year if from_time else 1 - years_to = datetime.date.today().year - 1 + years_to = timezone.now().year - 1 if stats_type == "yearly/affiliation": @@ -909,7 +909,7 @@ def meeting_stats(request, num=None, stats_type=None): continents = {} - meetings = Meeting.objects.filter(type='ietf', date__lte=datetime.date.today()).order_by('number') + meetings = Meeting.objects.filter(type='ietf', date__lte=date_today()).order_by('number') for m in meetings: country = CountryName.objects.get(slug=m.country) continents[country.continent.name] = country.continent.name diff --git a/ietf/submit/forms.py b/ietf/submit/forms.py index 857e6879c..4715f9bb5 100644 --- a/ietf/submit/forms.py +++ b/ietf/submit/forms.py @@ -7,7 +7,6 @@ import os import re import datetime import email -import pytz import sys import tempfile import xml2rfc @@ -43,6 +42,7 @@ from ietf.submit.parsers.xml_parser import XMLParser from ietf.utils import log from ietf.utils.draft import PlaintextDraft from ietf.utils.text import normalize_text +from ietf.utils.timezone import date_today from ietf.utils.xmldraft import XMLDraft, XMLParseError @@ -80,7 +80,7 @@ class SubmissionBaseUploadForm(forms.Form): self.base_formats = None # None will raise an exception in clean() if this isn't changed in a subclass def set_cutoff_warnings(self): - now = timezone.now().astimezone(pytz.utc) + now = timezone.now() meeting = Meeting.get_current_meeting() if not meeting: return @@ -156,7 +156,7 @@ class SubmissionBaseUploadForm(forms.Form): raise forms.ValidationError('The submission tool is currently shut down') # check general submission rate thresholds before doing any more work - today = datetime.date.today() + today = date_today() self.check_submissions_thresholds( "for the same submitter", dict(remote_ip=self.remote_ip, submission_date=today), @@ -573,7 +573,7 @@ class DeprecatedSubmissionBaseUploadForm(SubmissionBaseUploadForm): raise forms.ValidationError(mark_safe(self.cutoff_warning)) # check thresholds - today = datetime.date.today() + today = date_today() self.check_submissions_thresholds( "for the draft %s" % self.filename, diff --git a/ietf/submit/mail.py b/ietf/submit/mail.py index 16d1f0973..81d2233af 100644 --- a/ietf/submit/mail.py +++ b/ietf/submit/mail.py @@ -4,7 +4,6 @@ import re import email -import datetime import base64 import os import pyzmail @@ -28,6 +27,8 @@ from ietf.utils.accesstoken import generate_access_token from ietf.mailtrigger.utils import gather_address_lists, get_base_submission_message_address from ietf.submit.models import SubmissionEmailEvent, Submission from ietf.submit.checkers import DraftIdnitsChecker +from ietf.utils.timezone import date_today + def send_submission_confirmation(request, submission, chair_notice=False): subject = 'Confirm submission of I-D %s' % submission.name @@ -299,7 +300,7 @@ def add_submission_email(request, remote_ip, name, rev, submission_pk, message, rev=rev, title=name, note="", - submission_date=datetime.date.today(), + submission_date=date_today(), replaces="", ) from ietf.submit.utils import create_submission_event, docevent_from_submission diff --git a/ietf/submit/migrations/0012_use_date_today_helper.py b/ietf/submit/migrations/0012_use_date_today_helper.py new file mode 100644 index 000000000..3a02552f6 --- /dev/null +++ b/ietf/submit/migrations/0012_use_date_today_helper.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.28 on 2022-10-18 15:43 + +from django.db import migrations, models +import ietf.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('submit', '0011_use_timezone_now_for_submit_models'), + ] + + operations = [ + migrations.AlterField( + model_name='submission', + name='submission_date', + field=models.DateField(default=ietf.utils.timezone.date_today), + ), + ] diff --git a/ietf/submit/models.py b/ietf/submit/models.py index 629303296..0f9a86cd2 100644 --- a/ietf/submit/models.py +++ b/ietf/submit/models.py @@ -2,7 +2,6 @@ # -*- coding: utf-8 -*- -import datetime import email import jsonfield @@ -19,6 +18,7 @@ from ietf.name.models import DraftSubmissionStateName, FormalLanguageName from ietf.utils.accesstoken import generate_random_key, generate_access_token from ietf.utils.text import parse_unicode from ietf.utils.models import ForeignKey +from ietf.utils.timezone import date_today def parse_email_line(line): @@ -54,7 +54,7 @@ class Submission(models.Model): file_types = models.CharField(max_length=50, blank=True) file_size = models.IntegerField(null=True, blank=True) document_date = models.DateField(null=True, blank=True) - submission_date = models.DateField(default=datetime.date.today) + submission_date = models.DateField(default=date_today) xml_version = models.CharField(null=True, max_length=4, default=None) submitter = models.CharField(max_length=255, blank=True, help_text="Name and email of submitter, e.g. \"John Doe <john@example.org>\".") diff --git a/ietf/submit/parsers/base.py b/ietf/submit/parsers/base.py index 5c5d0d6fc..679798cc4 100644 --- a/ietf/submit/parsers/base.py +++ b/ietf/submit/parsers/base.py @@ -3,7 +3,6 @@ import re -import datetime import debug # pyflakes:ignore from typing import List, Optional # pyflakes:ignore @@ -12,6 +11,8 @@ from django.conf import settings from django.template.defaultfilters import filesizeformat from ietf.utils.mime import get_mime_type +from ietf.utils.timezone import date_today + class MetaData(object): rev = None @@ -60,7 +61,7 @@ class FileParser(object): self.parse_max_size(); self.parse_filename_extension() self.parse_file_type() - self.parsed_info.metadata.submission_date = datetime.date.today() + self.parsed_info.metadata.submission_date = date_today() return self.parsed_info def parse_invalid_chars_in_filename(self): diff --git a/ietf/submit/tests.py b/ietf/submit/tests.py index 86815f59f..9f6087d9b 100644 --- a/ietf/submit/tests.py +++ b/ietf/submit/tests.py @@ -52,6 +52,7 @@ from ietf.utils.accesstoken import generate_access_token from ietf.utils.mail import outbox, empty_outbox, get_payload_text from ietf.utils.models import VersionInfo from ietf.utils.test_utils import login_testing_unauthorized, TestCase +from ietf.utils.timezone import date_today from ietf.utils.draft import PlaintextDraft @@ -91,7 +92,7 @@ class BaseSubmitTestCase(TestCase): return settings.INTERNET_DRAFT_ARCHIVE_DIR def submission_file(name_in_doc, name_in_post, group, templatename, author=None, email=None, title=None, year=None, ascii=True): - _today = datetime.date.today() + _today = date_today() # construct appropriate text draft f = io.open(os.path.join(settings.BASE_DIR, "submit", templatename)) template = f.read() @@ -146,7 +147,7 @@ def create_draft_submission_with_rev_mismatch(rev='01'): sub = Submission.objects.create( name=draft_name, group=None, - submission_date=datetime.date.today() - datetime.timedelta(days=1), + submission_date=date_today() - datetime.timedelta(days=1), rev=rev, state_id='posted', ) @@ -164,7 +165,7 @@ class SubmitTests(BaseSubmitTestCase): def setUp(self): super().setUp() # Submit views assume there is a "next" IETF to look for cutoff dates against - MeetingFactory(type_id='ietf', date=datetime.date.today()+datetime.timedelta(days=180)) + MeetingFactory(type_id='ietf', date=date_today()+datetime.timedelta(days=180)) def create_and_post_submission(self, name, rev, author, group=None, formats=("txt",), base_filename=None): """Helper to create and post a submission @@ -1355,7 +1356,7 @@ class SubmitTests(BaseSubmitTestCase): # edit mailbox_before = len(outbox) # FIXME If this test is started before midnight, and ends after, it will fail - document_date = datetime.date.today() - datetime.timedelta(days=-3) + document_date = date_today() - datetime.timedelta(days=-3) r = self.client.post(edit_url, { "edit-title": "some title", "edit-rev": "00", @@ -1523,7 +1524,7 @@ class SubmitTests(BaseSubmitTestCase): def test_expire_submissions(self): s = Submission.objects.create(name="draft-ietf-mars-foo", group=None, - submission_date=datetime.date.today() - datetime.timedelta(days=10), + submission_date=date_today() - datetime.timedelta(days=10), rev="00", state_id="uploaded") @@ -1557,7 +1558,7 @@ class SubmitTests(BaseSubmitTestCase): # Put today in the blackout period meeting = Meeting.get_current_meeting() - meeting.importantdate_set.create(name_id='idcutoff',date=datetime.date.today()-datetime.timedelta(days=2)) + meeting.importantdate_set.create(name_id='idcutoff',date=date_today()-datetime.timedelta(days=2)) # regular user, no access r = self.client.get(url) @@ -1576,30 +1577,30 @@ class SubmitTests(BaseSubmitTestCase): url = urlreverse('ietf.submit.views.upload_submission') meeting = Meeting.get_current_meeting() - meeting.date = datetime.date.today()+datetime.timedelta(days=7) + meeting.date = date_today()+datetime.timedelta(days=7) meeting.save() meeting.importantdate_set.filter(name_id='idcutoff').delete() - meeting.importantdate_set.create(name_id='idcutoff', date=datetime.date.today()+datetime.timedelta(days=7)) + meeting.importantdate_set.create(name_id='idcutoff', date=date_today()+datetime.timedelta(days=7)) r = self.client.get(url) self.assertEqual(r.status_code,200) q = PyQuery(r.content) self.assertEqual(len(q('input[type=file][name=txt]')), 1) meeting = Meeting.get_current_meeting() - meeting.date = datetime.date.today() + meeting.date = date_today() meeting.save() meeting.importantdate_set.filter(name_id='idcutoff').delete() - meeting.importantdate_set.create(name_id='idcutoff', date=datetime.date.today()) + meeting.importantdate_set.create(name_id='idcutoff', date=date_today()) r = self.client.get(url) self.assertEqual(r.status_code,200) q = PyQuery(r.content) self.assertEqual(len(q('input[type=file][name=txt]')), 1) meeting = Meeting.get_current_meeting() - meeting.date = datetime.date.today()-datetime.timedelta(days=1) + meeting.date = date_today()-datetime.timedelta(days=1) meeting.save() meeting.importantdate_set.filter(name_id='idcutoff').delete() - meeting.importantdate_set.create(name_id='idcutoff', date=datetime.date.today()-datetime.timedelta(days=1)) + meeting.importantdate_set.create(name_id='idcutoff', date=date_today()-datetime.timedelta(days=1)) r = self.client.get(url) self.assertEqual(r.status_code,200) q = PyQuery(r.content) @@ -1864,7 +1865,7 @@ class SubmitTests(BaseSubmitTestCase): self.index += 1 sub = Submission.objects.create(name="draft-ietf-mars-bar-%d" % self.index, group=Group.objects.get(acronym="mars"), - submission_date=datetime.date.today(), + submission_date=date_today(), authors=[dict(name=self.author.name, email=self.author.user.email, affiliation='affiliation', @@ -2136,17 +2137,17 @@ class ApprovalsTestCase(BaseSubmitTestCase): Submission.objects.create(name="draft-ietf-mars-foo", group=Group.objects.get(acronym="mars"), - submission_date=datetime.date.today(), + submission_date=date_today(), rev="00", state_id="posted") Submission.objects.create(name="draft-ietf-mars-bar", group=Group.objects.get(acronym="mars"), - submission_date=datetime.date.today(), + submission_date=date_today(), rev="00", state_id="grp-appr") Submission.objects.create(name="draft-ietf-mars-quux", group=Group.objects.get(acronym="mars"), - submission_date=datetime.date.today(), + submission_date=date_today(), rev="00", state_id="ad-appr") @@ -2295,11 +2296,11 @@ class ManualPostsTestCase(BaseSubmitTestCase): Submission.objects.create(name="draft-ietf-mars-foo", group=Group.objects.get(acronym="mars"), - submission_date=datetime.date.today(), + submission_date=date_today(), state_id="manual") Submission.objects.create(name="draft-ietf-mars-bar", group=Group.objects.get(acronym="mars"), - submission_date=datetime.date.today(), + submission_date=date_today(), rev="00", state_id="grp-appr") @@ -2885,7 +2886,7 @@ class ApiSubmissionTests(BaseSubmitTestCase): class SubmissionUploadFormTests(BaseSubmitTestCase): def test_check_submission_thresholds(self): - today = datetime.date.today() + today = date_today() yesterday = today - datetime.timedelta(days=1) (this_group, that_group) = GroupFactory.create_batch(2, type_id='wg') this_ip = '10.0.0.1' @@ -3101,7 +3102,7 @@ class AsyncSubmissionTests(BaseSubmitTestCase): """Tests of async submission-related tasks""" def test_process_uploaded_submission(self): """process_uploaded_submission should properly process a submission""" - _today = datetime.date.today() + _today = date_today() xml, author = submission_file('draft-somebody-test-00', 'draft-somebody-test-00.xml', None, 'test_submission.xml') xml_data = xml.read() xml.close() @@ -3389,7 +3390,7 @@ class ApiSubmitTests(BaseSubmitTestCase): super().setUp() # break early in case of missing configuration self.assertTrue(os.path.exists(settings.IDSUBMIT_IDNITS_BINARY)) - MeetingFactory(type_id='ietf', date=datetime.date.today()+datetime.timedelta(days=60)) + MeetingFactory(type_id='ietf', date=date_today()+datetime.timedelta(days=60)) def do_post_submission(self, rev, author=None, name=None, group=None, email=None, title=None, year=None): url = urlreverse('ietf.submit.views.api_submit') diff --git a/ietf/submit/utils.py b/ietf/submit/utils.py index e1d383418..6fb0a36b6 100644 --- a/ietf/submit/utils.py +++ b/ietf/submit/utils.py @@ -48,6 +48,7 @@ from ietf.utils.accesstoken import generate_random_key from ietf.utils.draft import PlaintextDraft from ietf.utils.mail import is_valid_email from ietf.utils.text import parse_unicode, normalize_text +from ietf.utils.timezone import date_today from ietf.utils.xmldraft import XMLDraft from ietf.person.name import unidecode_name @@ -726,7 +727,7 @@ def recently_approved_by_user(user, since): ) def expirable_submissions(older_than_days): - cutoff = datetime.date.today() - datetime.timedelta(days=older_than_days) + cutoff = date_today() - datetime.timedelta(days=older_than_days) return Submission.objects.exclude(state__in=("cancel", "posted")).filter(submission_date__lt=cutoff) def expire_submission(submission, by): @@ -849,7 +850,7 @@ def fill_in_submission(form, submission, authors, abstract, file_size): submission.file_size = file_size submission.file_types = ','.join(form.file_types) submission.xml_version = form.xml_version - submission.submission_date = datetime.date.today() + submission.submission_date = date_today() submission.replaces = "" if form.parsed_draft is not None: submission.pages = form.parsed_draft.get_pagecount() diff --git a/ietf/submit/views.py b/ietf/submit/views.py index bab859702..9dcb88d13 100644 --- a/ietf/submit/views.py +++ b/ietf/submit/views.py @@ -48,6 +48,8 @@ from ietf.utils.accesstoken import generate_access_token from ietf.utils.log import log from ietf.utils.mail import parseaddr, send_mail_message from ietf.utils.response import permission_denied +from ietf.utils.timezone import date_today + def upload_submission(request): if request.method == 'POST': @@ -161,7 +163,7 @@ def api_submission(request): submission.state = DraftSubmissionStateName.objects.get(slug="validating") submission.remote_ip = form.remote_ip submission.file_types = ','.join(form.file_types) - submission.submission_date = datetime.date.today() + submission.submission_date = date_today() submission.submitter = user.person.formatted_email() submission.replaces = form.cleaned_data['replaces'] submission.save() @@ -723,7 +725,7 @@ def approvals(request): preapprovals = preapprovals_for_user(request.user) days = 30 - recently_approved = recently_approved_by_user(request.user, datetime.date.today() - datetime.timedelta(days=days)) + recently_approved = recently_approved_by_user(request.user, date_today() - datetime.timedelta(days=days)) return render(request, 'submit/approvals.html', {'selected': 'approvals', diff --git a/ietf/templates/person/profile.html b/ietf/templates/person/profile.html index 6732804aa..3d0b1e067 100644 --- a/ietf/templates/person/profile.html +++ b/ietf/templates/person/profile.html @@ -62,7 +62,7 @@ </tbody> </table> {% else %} - <p>{{ person.first_name }} has no active roles as of {{ today }}.</p> + <p>{{ person.first_name }} has no active roles as of {{ today|date:"Y-m-d" }}.</p> {% endif %} {% endif %} {% if person.personextresource_set.exists %} @@ -123,7 +123,7 @@ </tbody> </table> {% else %} - {{ person.first_name }} has no RFCs as of {{ today }}. + {{ person.first_name }} has no RFCs as of {{ today|date:"Y-m-d" }}. {% endif %} <h2 class="mt-5" id="drafts-{{ forloop.counter }}"> Active Drafts <small class="text-muted">({{ person.active_drafts|length }})</small> @@ -137,7 +137,7 @@ {% endfor %} </ul> {% else %} - {{ person.first_name }} has no active drafts as of {{ today }}. + {{ person.first_name }} has no active drafts as of {{ today|date:"Y-m-d" }}. {% endif %} <h2 class="mt-5"> Expired Drafts <small class="text-muted">({{ person.expired_drafts|length }})</small> @@ -156,7 +156,7 @@ </ul> (Excluding replaced drafts.) {% else %} - {{ person.first_name }} has no expired drafts as of {{ today }}. + {{ person.first_name }} has no expired drafts as of {{ today|date:"Y-m-d" }}. {% endif %} {% if person.has_drafts %} <h2 class="mt-5"> diff --git a/ietf/utils/draft.py b/ietf/utils/draft.py index 12a614701..0a379b0e9 100755 --- a/ietf/utils/draft.py +++ b/ietf/utils/draft.py @@ -50,6 +50,9 @@ import time from typing import Dict, List # pyflakes:ignore +from .timezone import date_today + + version = "0.35" program = os.path.basename(sys.argv[0]) progdir = os.path.dirname(sys.argv[0]) @@ -467,7 +470,7 @@ class PlaintextDraft(Draft): month = int(mon) else: continue - today = datetime.date.today() + today = date_today() if day==0: # if the date was given with only month and year, use # today's date if month and year is today's month and diff --git a/ietf/utils/test_data.py b/ietf/utils/test_data.py index cd5a06e83..2c6f048a5 100644 --- a/ietf/utils/test_data.py +++ b/ietf/utils/test_data.py @@ -21,6 +21,7 @@ from ietf.person.models import Person, Email from ietf.group.utils import setup_default_community_list_for_group from ietf.review.models import (ReviewRequest, ReviewerSettings, ReviewResultName, ReviewTypeName, ReviewTeamSettings ) from ietf.person.name import unidecode_name +from ietf.utils.timezone import date_today def create_person(group, role_name, name=None, username=None, email_address=None, password=None, is_staff=False, is_superuser=False): @@ -52,7 +53,7 @@ def make_immutable_base_data(): all tests in a run.""" # telechat dates - t = datetime.date.today() + datetime.timedelta(days=1) + t = date_today() + datetime.timedelta(days=1) old = TelechatDate.objects.create(date=t - datetime.timedelta(days=14)).date # pyflakes:ignore date1 = TelechatDate.objects.create(date=t).date # pyflakes:ignore date2 = TelechatDate.objects.create(date=t + datetime.timedelta(days=14)).date # pyflakes:ignore @@ -365,7 +366,7 @@ def make_test_data(): ietf72 = Meeting.objects.create( number="72", type_id="ietf", - date=datetime.date.today() + datetime.timedelta(days=180), + date=date_today() + datetime.timedelta(days=180), city="New York", country="US", time_zone="US/Eastern", diff --git a/ietf/utils/test_runner.py b/ietf/utils/test_runner.py index 914abc8e2..dd492e58a 100644 --- a/ietf/utils/test_runner.py +++ b/ietf/utils/test_runner.py @@ -40,7 +40,6 @@ import os import sys import time import json -import pytz import importlib import socket import gzip @@ -754,7 +753,7 @@ class IetfTestRunner(DiscoverRunner): with io.open(self.coverage_file, encoding='utf-8') as file: self.coverage_master = json.load(file) self.coverage_data = { - "time": timezone.now().astimezone(pytz.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), + "time": timezone.now().strftime("%Y-%m-%dT%H:%M:%SZ"), "template": { "coverage": 0.0, "covered": {}, diff --git a/ietf/utils/timezone.py b/ietf/utils/timezone.py index 58913f68d..0aeedbeda 100644 --- a/ietf/utils/timezone.py +++ b/ietf/utils/timezone.py @@ -3,6 +3,7 @@ import datetime from typing import Union from zoneinfo import ZoneInfo +from django.conf import settings from django.utils import timezone @@ -52,16 +53,22 @@ def datetime_from_date(date, tz=None): def datetime_today(tz=None): """Get a timezone-aware datetime representing midnight today + By default, uses settings.TIME_ZONE For use with datetime fields representing a date. """ + if tz is None: + tz = settings.TIME_ZONE return timezone.now().astimezone(_tzinfo(tz)).replace(hour=0, minute=0, second=0, microsecond=0) def date_today(tz=None): """Get the date corresponding to the current moment + By default, uses settings.TIME_ZONE Note that Dates are not themselves timezone aware. """ + if tz is None: + tz = settings.TIME_ZONE return timezone.now().astimezone(_tzinfo(tz)).date()