1 """Collecting Day and date-related items."""
2 from __future__ import annotations
3 from datetime import datetime, timedelta
4 from plomtask.db import DatabaseConnection, BaseModel
5 from plomtask.todos import Todo
6 from plomtask.dating import (DATE_FORMAT, valid_date)
9 class Day(BaseModel[str]):
10 """Individual days defined by their dates."""
14 def __init__(self, date: str, comment: str = '') -> None:
15 id_ = valid_date(date)
17 self.datetime = datetime.strptime(self.date, DATE_FORMAT)
18 self.comment = comment
19 self.calendarized_todos: list[Todo] = []
21 def __lt__(self, other: Day) -> bool:
22 return self.date < other.date
25 def all(cls, db_conn: DatabaseConnection,
26 date_range: tuple[str, str] = ('', ''),
27 fill_gaps: bool = False) -> list[Day]:
28 """Return list of Days in database within (open) date_range interval.
30 On fill_gaps=True, will instantiate (without saving) Days of all dates
31 within the date range that don't exist yet.
33 ret = cls.by_date_range_with_limits(db_conn, date_range, 'id')
34 days, start_date, end_date = ret
37 if start_date not in [d.date for d in days]:
38 days = [Day(start_date)] + days
39 if end_date not in [d.date for d in days]:
40 days += [Day(end_date)]
43 for i, day in enumerate(days):
46 while day.next_date != days[i+1].date:
47 day = Day(day.next_date)
53 def date(self) -> str:
54 """Return self.id_ under the assumption it's a date string."""
55 assert isinstance(self.id_, str)
59 def first_of_month(self) -> bool:
60 """Return what month self.date is part of."""
61 assert isinstance(self.id_, str)
62 return self.id_[-2:] == '01'
65 def month_name(self) -> str:
66 """Return what month self.date is part of."""
67 return self.datetime.strftime('%B')
70 def weekday(self) -> str:
71 """Return what weekday matches self.date."""
72 return self.datetime.strftime('%A')
75 def prev_date(self) -> str:
76 """Return date preceding date of this Day."""
77 prev_datetime = self.datetime - timedelta(days=1)
78 return prev_datetime.strftime(DATE_FORMAT)
81 def next_date(self) -> str:
82 """Return date succeeding date of this Day."""
83 next_datetime = self.datetime + timedelta(days=1)
84 return next_datetime.strftime(DATE_FORMAT)
86 def collect_calendarized_todos(self, db_conn: DatabaseConnection) -> None:
87 """Fill self.calendarized_todos."""
88 self.calendarized_todos = [t for t in Todo.by_date(db_conn, self.date)