grandfatherson/filters.py
def filter(cls, datetimes, number, now=None, **options):
        """Return a set of datetimes, after filtering ``datetimes``.

        The result will be the ``datetimes`` which are ``number`` of
        units before ``now``, until ``now``, with approximately one
        unit between each of them.  The first datetime for any unit is
        kept, later duplicates are removed.

        If there are ``datetimes`` after ``now``, they will be
        returned unfiltered.
        """
        if not isinstance(number, int) or number < 0:
            raise ValueError('Invalid number: %s' % number)

        datetimes = tuple(datetimes)

        # Sample the first datetime to see if it is timezone-aware
        tzinfo = None
        if datetimes and datetimes[0].tzinfo is not None:
            tzinfo = UTC()

        if now is None:
            now = datetime.now(tzinfo)

        if not hasattr(now, 'second'):
            # now looks like a date, so convert it into a datetime
            now = datetime.combine(now, time(23, 59, 59, 999999, tzinfo=tzinfo))

        # Always keep datetimes from the future
        future = set(dt for dt in datetimes if dt > now)

        if number == 0:
            return future

        # Don't consider datetimes from before the start
        start = cls.start(now, number, **options)
        valid = (dt for dt in datetimes if start <= dt <= now)

        # Deduplicate datetimes with the same mask() value by keeping
        # the oldest.
        kept = {}
        for dt in sorted(valid):
            kept.setdefault(cls.mask(dt, **options), dt)

        return set(kept.values()) | future
def filter(cls, datetimes, number, now=None, **options):
        """Return a set of datetimes, after filtering ``datetimes``.

        The result will be the ``datetimes`` which are ``number`` of
        units before ``now``, until ``now``, with approximately one
        unit between each of them.  The first datetime for any unit is
        kept, later duplicates are removed.

        If there are ``datetimes`` after ``now``, they will be
        returned unfiltered.
        """
        if not isinstance(number, int) or number < 0:
            raise ValueError('Invalid number: %s' % number)

        datetimes = tuple(datetimes)

        # Sample the first datetime to see if it is timezone-aware
        tzinfo = None
        if datetimes and datetimes[0].tzinfo is not None:
            tzinfo = UTC()

        if now is None:
            now = datetime.now(tzinfo)

        if not hasattr(now, 'second'):
            # now looks like a date, so convert it into a datetime
            now = datetime.combine(now, time(23, 59, 59, 999999, tzinfo=tzinfo))

        # Always keep datetimes from the future
        future = set(dt for dt in datetimes if dt > now)

        if number == 0:
            return future

        # Don't consider datetimes from before the start
        start = cls.start(now, number, **options)
        valid = (dt for dt in datetimes if start <= dt <= now)

        # Deduplicate datetimes with the same mask() value by keeping
        # the oldest.
        kept = {}
        for dt in sorted(valid):
            kept.setdefault(cls.mask(dt, **options), dt)

        return set(kept.values()) | future
Return a set of datetimes, after filtering ``datetimes``.

        The result will be the ``datetimes`` which are ``number`` of
        units before ``now``, until ``now``, with approximately one
        unit between each of them.  The first datetime for any unit is
        kept, later duplicates are removed.

        If there are ``datetimes`` after ``now``, they will be
        returned unfiltered.