Source code for finalynx.simulator.recurrence

from datetime import date
from datetime import timedelta
from typing import Optional


[docs]class RecurrenceBase: """Abstract class to define how often an Event should be triggered.""" def __init__(self, until: Optional[date] = None) -> None: self.until = until
[docs] def next(self, current_date: date) -> Optional[date]: next_date = self._next_date(current_date) if self.until and next_date > self.until: return None return next_date
[docs] def _next_date(self, current_date: date) -> date: raise NotImplementedError("Must be overridden by subclass.")
[docs]class DeltaRecurrence(RecurrenceBase): """Program an action to happen every few days/months/years.""" def __init__( self, days: Optional[int] = None, months: Optional[int] = None, years: Optional[int] = None, until: Optional[date] = None, ) -> None: super().__init__(until) assert days is not None or months is not None or years is not None, "Set at least one time field" days = days if days is not None else 0 months = months if months is not None else 0 years = years if years is not None else 0 # Add decimals to stay on the same day (otherwise Yearly goes to 30/12) self._delta = timedelta(days, weeks=4.3452 * months + 52.1429 * years + 0.1429)
[docs] def _next_date(self, current_date: date) -> date: return current_date + self._delta
[docs]class MonthlyRecurrence(RecurrenceBase): """Program an action to happen every nth day of the month.""" def __init__( self, day_of_the_month: int, n_months: int = 1, until: Optional[date] = None, ) -> None: """Program an action to happen every nth day of the month. :param n_months: Optionally skip some months. """ super().__init__(until) self.day_of_the_month = day_of_the_month self.n_months = n_months
[docs] def _next_date(self, current_date: date) -> date: next_month = current_date.month + self.n_months if next_month > 12: return date(current_date.year + 1, next_month - 12, self.day_of_the_month) return date(current_date.year, next_month, self.day_of_the_month)