def recurrence_int_sequence(sequence): """ Generates a sequence of integer representations from a sequence of dateime instances. """ for dt in sequence: yield dt2int(dt)
def test_dt2int_less_MAX32(self, utc): from plone.event.utils import dt2int dt = mock.Mock() dd = mock.Mock() utc.return_value = dd dd.year = 2011 dd.month = 11 dd.day = 24 dd.hour = 14 dd.minute = 16 self.assertRaises(OverflowError, lambda: dt2int(dt))
def recurrence_int_sequence(sequence): """ Generates a sequence of integer representations from a sequence of dateime instances. :param sequence: An iterable sequence of datetime instances. :type sequence: iterable :returns: Generator of integer representations of datetime instances. :rtype: generator """ for dt in sequence: yield dt2int(dt)
def test_dt2int_more_MAX32(self, utc): from plone.event.utils import dt2int dt = mock.Mock() dd = mock.Mock() utc.return_value = dd dd.year = 2011 dd.month = 11 dd.day = 24 dd.hour = 14 dd.minute = 16 value = 1077778936 self.assertEqual(dt2int(dt), value)
def filter_and_resort(context, brains, start, end, sort, sort_reverse): """#114 sorting bug is fallout from a Products.DateRecurringIndex limitation. The index contains a set of start and end dates represented as integer: that allows valid slicing of searches. However the returned brains have a .start attribute which is the start DateTime of the *first* occurrence of an event. This results in mis-sorting of search results if the next occurrence of event B is after the next occurrence of event A, but the first occurrence of event B is *before* the first occurrence of event A. The catalog results sort that as B<A instead of A<B. This method works around that issue by extracting all occurrence start/end from the index, and then sorting on the actual next start/end. For ongoing events which have an occurrence starting in the past but ending in the future, the past start of that ongoing occurrence is selected, so this will show up right at the start of the result. :param context: [required] A context object. :type context: Content object :param brains: [required] catalog brains :type brains: catalog brains :param start: [required] min end datetime (sic!) :type start: Python datetime. :param end: [required] max start datetime (sic!) :type start: Python datetime. :param sort_reverse: Change the order of the sorting. :type sort_reverse: boolean :param sort: Which field to sort on :type sort: 'start' or 'end' :returns: catalog brains :rtype: catalog brains """ _start = dt2int(start) # index contains longint sets _end = dt2int(end) catalog = getToolByName(context, 'portal_catalog') items = [] # (start:int, occurrence:brain) pairs for brain in brains: # brain.start metadata reflects first occurrence. # instead, get all occurrence start/end from raw index idx = catalog.getIndexDataForRID(brain.getRID()) _allstarts = sorted(idx['start']) _allends = sorted(idx['end']) # assuming (start, end) pairs belong together # assert(len(_allstarts) == len(_allends)) _occ = six.moves.zip(_allstarts, _allends) if start: _occ = [(s, e) for (s, e) in _occ if e >= _start] if end: _occ = [(s, e) for (s, e) in _occ if s <= _end] if not _occ: continue if sort == 'start': # first start can be before filter window if end is in window _first = min([s for (s, e) in _occ]) elif sort == 'end': _first = min([e for (s, e) in _occ]) items.append((_first, brain)) # key on next start/end # sort brains by next start, discard sort key data = [x[1] for x in sorted(items, key=lambda x: x[0])] if sort_reverse: data.reverse() return data
def filter_and_resort(context, brains, start, end, sort, sort_reverse): """#114 sorting bug is fallout from a Products.DateRecurringIndex limitation. The index contains a set of start and end dates represented as integer: that allows valid slicing of searches. However the returned brains have a .start attribute which is the start DateTime of the *first* occurrence of an event. This results in mis-sorting of search results if the next occurrence of event B is after the next occurrence of event A, but the first occurrence of event B is *before* the first occurrence of event A. The catalog results sort that as B<A instead of A<B. This method works around that issue by extracting all occurrence start/end from the index, and then sorting on the actual next start/end. For ongoing events which have an occurrence starting in the past but ending in the future, the past start of that ongoing occurrence is selected, so this will show up right at the start of the result. :param context: [required] A context object. :type context: Content object :param brains: [required] catalog brains :type brains: catalog brains :param start: [required] min end datetime (sic!) :type start: Python datetime. :param end: [required] max start datetime (sic!) :type start: Python datetime. :param sort_reverse: Change the order of the sorting. :type sort_reverse: boolean :param sort: Which field to sort on :type sort: 'start' or 'end' :returns: catalog brains :rtype: catalog brains """ _start = dt2int(start) # index contains longint sets _end = dt2int(end) catalog = getToolByName(context, 'portal_catalog') items = [] # (start:int, occurrence:brain) pairs for brain in brains: # brain.start metadata reflects first occurrence. # instead, get all occurrence start/end from raw index idx = catalog.getIndexDataForRID(brain.getRID()) _allstarts = sorted(idx['start']) _allends = sorted(idx['end']) # assuming (start, end) pairs belong together #assert(len(_allstarts) == len(_allends)) _occ = itertools.izip(_allstarts, _allends) if start: _occ = [(s, e) for (s, e) in _occ if e >= _start] if end: _occ = [(s, e) for (s, e) in _occ if s <= _end] if not _occ: continue if sort == 'start': # first start can be before filter window if end is in window _first = min([s for (s, e) in _occ]) elif sort == 'end': _first = min([e for (s, e) in _occ]) items.append((_first, brain)) # key on next start/end # sort brains by next start, discard sort key data = [x[1] for x in sorted(items, key=lambda x: x[0])] if sort_reverse: data.reverse() return data
def _convert(self, value, default=None): """Convert record keys/datetimes into int representation. """ return dt2int(value) or default
def test_dt2int_dt_is_None(self): from plone.event.utils import dt2int self.assertFalse(dt2int(None))