Exemple #1
0
 def test_quarter(self):
     dates = [
         datetime.date(2019, 1, 1),
         datetime.date(2019, 6, 30),
         datetime.date(2019, 7, 1),
         datetime.date(2019, 12, 31),
     ]
     self.assertEqual([utils.quarter(date) for date in dates], [1, 2, 3, 4])
Exemple #2
0
    def eoq(self, date: datetime.date) -> datetime.date:
        """
        Returns the last open date of the quarter

        Parameters
        ----------
        date : datetime.date
            the date from which to compute the end of quarter

        Returns
        -------
        datetime.date
        """
        for i in range(self.index(date), len(self)):
            if (utils.quarter(self.__dates__[i]) == utils.quarter(date)
                    and self.__dates__[i].year == date.year):
                continue
            return self.__dates__[i - 1]
        return self.__dates__[i]
Exemple #3
0
    def soq(self, date: datetime.date) -> datetime.date:
        """
        Returns the first open day of the quarter given the date

        Parameters
        ----------
        date : datetime.date
            the date from which to compute the start of the quarter

        Returns
        -------
        datetime.date
        """
        for i in range(self.index(date), -1, -1):
            if (utils.quarter(self.__dates__[i]) == utils.quarter(date)
                    and self.__dates__[i].year == date.year):
                continue
            return self.__dates__[i + 1]
        return self.__dates__[i]
Exemple #4
0
    def groupby(self, grouper):
        """
        Group dates by the grouper parameter. 

        Allowed values for the grouper: 
            - callable - the callable will receive the date and must return a hashable value
            - frequency criterion - a string representing a frequency 

        Frequency criteria include: 
            - :code:`W`: group by week number each year
            - :code:`M`: group by month each year
            - :code:`Q`: group by quarter each year
            - :code:`H`: group by semester each year
            - :code:`Y`: group by year each year
        
        Parameters
        ----------
        grouper : str, callable
            the criterion to group dates by

        Returns
        -------
        :class:`doubledate.calendar.Collection`
            Collection of calendars    

        Example
        -------
        Group dates by month

        >>> calendar = Calendar(dates)
        >>> calendar.groupby("M")
        <doubledate.Collection at 0x7fd0fa52c2e0>

        Group dates in half months

        >>> calendar = Calendar(dates)
        >>> calendar.groupby(lambda date: (date.year, date.month, date.day < 15))
        <doubledate.Collection at 0x7fd0fa52c2e0>

        """
        if isinstance(grouper, str):
            if grouper == "W":
                return self.groupby(lambda date:
                                    (date.year, date.isocalendar()[1]))
            elif grouper == "M":
                return self.groupby(lambda date: (date.year, date.month))
            elif grouper == "Q":
                return self.groupby(lambda date:
                                    (date.year, utils.quarter(date)))
            elif grouper == "H":
                return self.groupby(lambda date: (date.year, date.month > 6))
            elif grouper == "Y":
                return self.groupby(lambda date: date.year)
            raise ValueError(
                f"Expected one of 'W', 'M', 'Q', 'H' or 'Y'; '{grouper}' given"
            )

        if callable(grouper):
            calendars = collections.defaultdict(lambda: [])
            for date in self:
                calendars[grouper(date)].append(date)
            return Collection(
                [Calendar(dates) for dates in calendars.values()])

        raise ValueError(f"Expected string or function, received '{grouper}'")
Exemple #5
0
    def filter(
        self,
        func=None,
        *,
        year: int = None,
        semester: int = None,
        quarter: int = None,
        month: int = None,
        week: int = None,
        weekday: str = None,
    ):
        """
        Filters and returns a new calendar from this calendar based 
        on a criteria. 

        Allowed criteria are: 
        - either a filtering function (lambda)
        - one or several filtering frequencies as named arguments

        Parameters
        ----------
        func : function, optional
            a filtering function (receives each date as argument)
        year : int, optional
            pass a value to filter dates of the given year only
        semester : int, optional (1 or 2)
            pass a value to filter dates of the given semester only
        quarter : int, optional (1, 2, 3, or 4)
            pass a value to filter dates of the given quarter only
        month : int, optional (1 through 12)
            pass a value to filter dates of the given month only
        week : int, optional (1 through 53)
            pass a value to filter dates of the given week number only
        weekday : int, optional (0 through 6)
            pass a value to filter dates of the given weekday only
            Monday = 0, Tuesday = 1... Sunday = 6

        Returns
        -------
        Calendar

        Example 
        -------
        Filter dates from 3Q 2020
        >>> calendar = Calendar(dates) #assume dates is a list of dates
        >>> calendar.filter(year=2020, quarter=3)

        Filter Mondays
        >>> calendar = Calendar(dates)
        >>> calendar.filter(lambda date: date.weekday() == 0)
        """
        if func is not None:
            if not callable(func):
                raise ValueError(
                    "Filter accepts either a function, one or several named arguments"
                )
            return Calendar([date for date in self.__dates__ if func(date)])
        if all([
                arg is None
                for arg in [year, semester, quarter, month, week, weekday]
        ]):
            raise ValueError(
                "You need to provide one of year, semester, quarter, month, week, weekday"
            )
        dates = list(self.__dates__)
        if year is not None:
            dates = list(filter(lambda date: date.year == year, dates))
        if semester is not None:
            dates = list(
                filter(lambda date: utils.semester(date) == semester, dates))
        if quarter is not None:
            dates = list(
                filter(lambda date: utils.quarter(date) == quarter, dates))
        if month is not None:
            dates = list(filter(lambda date: date.month == month, dates))
        if week is not None:
            dates = list(
                filter(lambda date: date.isocalendar()[1] == week, dates))
        if weekday is not None:
            dates = list(filter(lambda date: date.weekday() == weekday, dates))
        return Calendar(dates)