diff options
Diffstat (limited to 'datamaps/core/temporal.py')
-rw-r--r-- | datamaps/core/temporal.py | 124 |
1 files changed, 100 insertions, 24 deletions
diff --git a/datamaps/core/temporal.py b/datamaps/core/temporal.py index ddb7004..a927b23 100644 --- a/datamaps/core/temporal.py +++ b/datamaps/core/temporal.py @@ -1,4 +1,67 @@ +import calendar import datetime +import itertools +from typing import List + +MONTHS = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", +] + + +class Month: + """An object representing a calendar Month.""" + + _end_ints = { + 1: 31, + 2: 28, + 3: 31, + 4: 30, + 5: 31, + 6: 30, + 7: 31, + 8: 31, + 9: 30, + 10: 31, + 11: 30, + 12: 31, + } + + def __init__(self, month: int, year: int): + self.month_int = month + self.year = year + + @property + def start_date(self): + return datetime.date(self.year, self.month_int, 1) + + @property + def end_date(self): + if self.month_int == 2 and calendar.isleap(self.year): + return datetime.date( + self.year, self.month_int, Month._end_ints[self.month_int] + 1 + ) + else: + return datetime.date( + self.year, self.month_int, Month._end_ints[self.month_int] + ) + + @property + def name(self): + return MONTHS[self.month_int - 1] + + def __repr__(self): + return f"Month({self.name})" class FinancialYear: @@ -26,27 +89,23 @@ class FinancialYear: self.end_date = self.q4.end_date @property - def q1(self) -> datetime.date: - """Quarter 1 as a :py:class:`datetime.date` object - """ + def q1(self): + """Quarter 1 as a :py:class:`datetime.date` object""" return self._q1 @property def q2(self): - """Quarter 2 as a :py:class:`datetime.date` object - """ + """Quarter 2 as a :py:class:`datetime.date` object""" return self._q2 @property def q3(self): - """Quarter 3 as a :py:class:`datetime.date` object - """ + """Quarter 3 as a :py:class:`datetime.date` object""" return self._q3 @property def q4(self): - """Quarter 4 as a :py:class:`datetime.date` object - """ + """Quarter 4 as a :py:class:`datetime.date` object""" return self._q4 def __str__(self): @@ -55,34 +114,35 @@ class FinancialYear: def _generate_quarters(self): self.quarters = [Quarter(x, self.year) for x in range(1, 5)] - def __repr__(self): return f"FinancialYear({self.year})" class Quarter: - """An object representing a financial quarter. This is mainly required for building - a :py:class:`core.master.Master` object. + """An object representing a financial quarter. + + This is mainly required for building a :py:class:`core.master.Master` + object. Args: quarter (int): e.g.1, 2, 3 or 4 year (int): e.g. 2013 """ + _start_months = { - 1: (4, 'April'), - 2: (7, 'July'), - 3: (10, 'October'), - 4: (1, 'January') + 1: (4, "April"), + 2: (7, "July"), + 3: (10, "October"), + 4: (1, "January"), } _end_months = { - 1: (6, 'June', 30), - 2: (9, 'September', 30), - 3: (12, 'December', 31), - 4: (3, 'March', 31), + 1: (6, "June", 30), + 2: (9, "September", 30), + 3: (12, "December", 31), + 4: (3, "March", 31), } - def __init__(self, quarter: int, year: int) -> None: if isinstance(quarter, int) and (quarter >= 1 and quarter <= 4): @@ -93,10 +153,27 @@ class Quarter: if isinstance(year, int) and (year in range(1950, 2100)): self.year = year else: - raise ValueError("Year must be between 1950 and 2100 - surely that will do?") + raise ValueError( + "Year must be between 1950 and 2100 - surely that will do?" + ) self.start_date = self._start_date(self.quarter, self.year) self.end_date = self._end_date(self.quarter, self.year) + self.months: List[Month] = [] + self._populate_months() + + def _populate_months(self): + months_ints = [] + start_int = Quarter._start_months[self.quarter][0] + strt = itertools.count(start_int) + for x in range(3): + months_ints.append(next(strt)) + for m in months_ints: + if self.quarter == 4: + year = self.year + 1 + else: + year = self.year + self.months.append(Month(m, year)) def __str__(self): return f"Q{self.quarter} {str(self.year)[2:]}/{str(self.year + 1)[2:]}" @@ -116,6 +193,5 @@ class Quarter: @property def fy(self): - """Return a :py:class:`core.temporal.FinancialYear` object. - """ + """Return a :py:class:`core.temporal.FinancialYear` object.""" return FinancialYear(self.year) |