Source code for neighborly.datetime

"""Simulation date representation.

Implements a 12 month calendar

"""

from __future__ import annotations

import copy
from typing import Any

MONTHS_PER_YEAR = 12
"""The number of months per calendar year."""


[docs]class SimDate: """Records the current date of the simulation counting in 1-month increments.""" __slots__ = "_month", "_year", "_total_months" _month: int """The current month""" _year: int """The current year""" _total_months: int """Total number of elapsed months""" def __init__(self, year: int = 1, month: int = 1) -> None: """ Parameters ---------- month The month of the year [1, 12], default 1 year The current year >= 1, default 1 """ if 1 <= month <= MONTHS_PER_YEAR: self._month = month - 1 else: raise ValueError( f"Parameter 'month' must be between 1 and {MONTHS_PER_YEAR}" ) if year >= 1: self._year = year - 1 else: raise ValueError("Parameter 'year' must be greater than or equal to 1.") self._total_months = self._month + (self._year * MONTHS_PER_YEAR) @property def month(self) -> int: """The current month of the year [1 - 12].""" return self._month + 1 @property def year(self) -> int: """The current year.""" return self._year + 1 @property def total_months(self) -> int: """Get the total number of elapsed months since month 1, year 1.""" return self._total_months
[docs] def increment_month(self) -> None: """Increments the month by one.""" self._month += 1 self._total_months += 1 if self._month == MONTHS_PER_YEAR: self._month = 0 self._year += 1
[docs] def increment(self, months: int = 0, years: int = 0) -> None: """Increment the date by the given time.""" carry_years, current_month = divmod(self._month + months, MONTHS_PER_YEAR) self._month = current_month self._total_months += months + (MONTHS_PER_YEAR * years) self._year += carry_years + years
[docs] def to_iso_str(self) -> str: """Create an ISO date string of format YYYY-MM. Returns ------- str The date string. """ return f"{self.year:04d}-{self.month:02d}"
[docs] def copy(self) -> SimDate: """Create a copy of this date.""" return copy.copy(self)
def __repr__(self) -> str: return f"{self.__class__.__name__}(month={self.month}, year={self.year})" def __copy__(self) -> SimDate: return SimDate(month=self.month, year=self.year) def __deepcopy__(self, memo: dict[str, Any]) -> SimDate: return SimDate(month=self.month, year=self.year) def __str__(self) -> str: return self.to_iso_str() def __le__(self, other: SimDate) -> bool: return self.total_months <= other.total_months def __lt__(self, other: SimDate) -> bool: return self.total_months < other.total_months def __ge__(self, other: SimDate) -> bool: return self.total_months >= other.total_months def __gt__(self, other: SimDate) -> bool: return self.total_months > other.total_months def __eq__(self, other: object) -> bool: if not isinstance(other, SimDate): raise TypeError(f"expected {type(self)} object but was {type(other)}") return self.total_months == other.total_months