aboutsummaryrefslogtreecommitdiffstats
path: root/datamaps/core/temporal.py
diff options
context:
space:
mode:
Diffstat (limited to 'datamaps/core/temporal.py')
-rw-r--r--datamaps/core/temporal.py124
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)