Ejemplo n.º 1
0
    def _build_occurrence(self):
        """
        Figure out which occurrence values are set and add them to the occurrence.
        Returns a string.
        """
        rr = self.__rrule
        bymonth = rr._bymonth # Tuple. Which month a yearly event recurs in.
        byweekno = rr._byweekno # Tuple. Which week number a yearly event recurs in.
        byyearday = rr._byyearday # Tuple. Which day of the year a yearly event recurs in.
        byweekday = rr._byweekday # Tuple. Which weekday an event recurs in.
        bynweekday = rr._bynweekday # Tuple. By the nth weekday, e.g., FR(3) is the third Friday of the period. Only used if freq is < MONTHLY
        byeaster = rr._byeaster # Tuple.
        bymonthday = rr._bymonthday # Tuple. Relative day of the month
        bynmonthday = rr._bynmonthday # Tuple. Relative day of the month, if negative (counting from the end of the month)
        bysetpos = rr._bysetpos # Tuple. For sets of seconds/minutes/hours/days/weeks/months/years, specifies which position in the list to pay attention to.
        byhour = rr._byhour # Tuple. The hour of the occurrence.
        byminute = rr._byminute # Tuple. The minutes of the occurrence.
        bysecond = rr._bysecond # Tuple. The second of the occurrence.
        
        o = ""
        if bymonth:
            for month in bymonth:
                o = " ".join([o, MONTH_MAP[month]])
                for i, monthday in enumerate(bymonthday):
                    o = "".join([", " if i>0 else "", o, " ", str(monthday)])                  
                    
        if bymonthday:
            if not bymonth:
                s = ""
                for i, monthday in enumerate(bymonthday):
                    s = "".join([" and " if i>0 else "", "the %s day of the month", human_rrule.int_as_ordinal(bymonthday[0])])
                o = "".join([o, s]) # 
        if bynmonthday:
            s = ""
            for i, nmonthday in enumerate(bynmonthday):                    
                s = "".join([" and " if i>0 else "", "the %s to last day of the month" % human_rrule.int_as_ordinal(bynmonthday)])
                o = "".join([o, s]) # 
        if byweekday:
            s = ""
            for i, p_weekday in enumerate(byweekday):
                s = "".join([", " if i>0 else "", WEEKDAY_MAP[unicode(weekday(p_weekday))]])
                o = "".join([o, s])
        if byweekno:
            o = " ".join([o, "the %s week" % human_rrule.int_as_ordinal(byweekno)])
        if byyearday:
            o = " ".join([o, "the %s year" % human_rrule.int_as_ordinal(byyearday)])
        if bynweekday:
            for rule_pair in bynweekday:

                # Get the ordinal. TODO handle multiple ordinals
                ord_text = []
                ord_text.append(human_rrule.int_as_ordinal(rule_pair[1]))

                #  Get the weekday name
                p_weekday = weekday(rule_pair[0])
                name = [WEEKDAY_MAP[unicode(p_weekday)]]
                ord_text.extend(name)
                o = " ".join([o, ord_text[0], ord_text[1]])
        
        return o
Ejemplo n.º 2
0
    def dict_to_object(self, d):
        if '__type__' not in d:
            return d

        objtype = d.pop('__type__')

        if objtype == 'datetime':
            return datetime(tzinfo=timezone.utc, **d)

        if objtype == 'interval':
            return schedule(run_every=d['every'], relative=d['relative'])

        if objtype == 'crontab':
            return crontab(**d)

        if objtype == 'weekday':
            return weekday(**d)

        if objtype == 'rrule':
            # Decode timestamp values into datetime objects
            for key, tz_key in [('dtstart', 'dtstart_tz'),
                                ('until', 'until_tz')]:
                timestamp = d.get(key)
                tz_minutes = d.pop(tz_key, 0)
                if timestamp is not None:
                    d[key] = from_timestamp(timestamp, tz_minutes)
            return rrule(**d)

        d['__type__'] = objtype

        return d
Ejemplo n.º 3
0
    def to_python(self, value):
        """
        Converts value assigned or read from database into correct
        format: set of day numbers.
        """
        if value is None or value == "":
            return None

        if isinstance(value, basestring):
            value = int(value)
            # and then process as usual

        if isinstance(value, int):
            # value is a mask of days
            if not 0 <= value <= 0b01111111:
                raise ValueError(repr(value))
            days = set()
            for i in xrange(7):
                if value & (1 << i):
                    days.add(weekday(i))
        else:
            days = set(value)

        if any(not isinstance(x, weekday) for x in days):
            raise ValueError("Days should be weekday objects: " + repr(days))
        if len(set(day.weekday for day in days)) != len(days):
            raise ValueError("Duplicate days: " + repr(days))
        return days
Ejemplo n.º 4
0
    def test_weekday(self):
        d = self.weekday()

        result = self.loads(json.dumps(d))

        d.pop('__type__')
        self.assertEqual(result, dateutil_rrule.weekday(5))
Ejemplo n.º 5
0
    def handle_byweekday(self):
        """
        a fork from dateutil.rrule source code
        """
        if not self.byweekday:
            return False

        weekday_dict = {
            "MO": 0,
            "TU": 1,
            "WE": 2,
            "TH": 3,
            "FR": 4,
            "SA": 5,
            "SU": 6
        }

        weekdays_constants = []
        for wday in self.byweekday:
            i = 0
            for i in range(len(wday)):
                if wday[i] not in '+-0123456789':
                    break
            n = wday[:i] or None
            w = wday[i:]
            if n:
                n = int(n)
            weekdays_constants.append(weekday(weekday_dict[w], n))
        return weekdays_constants
Ejemplo n.º 6
0
def calc_recurrence_pattern(start_date: dt.datetime, end_date: dt.datetime):
    """

    予定の繰り返しパターン文字列を生成する

    Args:
        start_date (datetime.datetime): パターンの開始日
        end_date (datetime.datetime): パターンの終了日

    Returns;
        str : RFC5545に準拠した繰り返しパターンの文字列

    Examples:
        calc_recurrence_pattern(date, "mon")
    """
    pattern = str(
        rr.rrule(
            freq=rr.WEEKLY,
            wkst=rr.SU,
            byweekday=rr.weekday(wkday=start_date.weekday()))).split("\n")[1]
    pattern = "".join([
        pattern,
        ";UNTIL=",
        end_date.astimezone(dt.timezone.utc).strftime("%Y%m%dT%H%M%SZ"),
    ])
    return pattern
Ejemplo n.º 7
0
 def testPassThruWkst(self):
     newWkst = (calendar.firstweekday() + 2) % 7
     self.failUnlessParseMatches(
         "FREQ=WEEKLY;INTERVAL=2;BYDAY=SU,FR;WKST=%s" % (
                                         rrule.weekday(newWkst)),
         True,
         {'freq':rrule.WEEKLY, 'interval':2,
          'byweekday':(rrule.SU, rrule.FR)},
         {'wkst': newWkst} # Test passthru of wkst
     )
Ejemplo n.º 8
0
 def _next_due_date(self) -> datetime.date:
     """ Calculates the next time item will appear in master list. """
     due_date, *_ = rrule(
         freq=self.todo_list.frequency,
         interval=self.todo_list.interval,
         count=1,
         dtstart=self.due_date + relativedelta(days=1),
         byweekday=(*[weekday(i) for i in self.todo_list.weekdays], ),
     )
     return due_date.date()
Ejemplo n.º 9
0
 def _get_start_of_period(self, dt):
     if self.rrule_type == 'weekly':
         lang = self.env['res.lang']._lang_get(self.env.user.lang)
         week_start = int(lang.week_start)  # lang.week_start ranges from '1' to '7'
         week_start = rrule.weekday(week_start - 1)  # expects an int from 0 to 6
         start = dt + relativedelta(weekday=week_start(-1))
     elif self.rrule_type == 'monthly':
         start = dt + relativedelta(day=1)
     else:
         start = dt
     return start
Ejemplo n.º 10
0
 def get_rrule(self):
     if self._rrule is None:
         # if it isn't cached, create it
         params = model_to_dict(self, fields=['dtstart', 'freq','until','count','interval','wkst','byweekday']) 
         params['wkst'] = rrule.weekday(params['wkst'])
         if len(self.byweekday) == 0:
             params.pop('byweekday')
         if not params['count'] and not params['until']:
             params['count'] = 1
         self._rrule = rrule.rrule(**params)
     return self._rrule
def week_day_every_month_generator(start, interval, local_date):
    start_week = (local_date.day - 1) / 7 + 1
    start_wday = start.weekday()

    # Use "Last" for 5-th week
    wday = weekday(start_wday, -1 if start_week == 5 else start_week)

    rule = rrule(freq=MONTHLY, dtstart=start, count=MAX_YEARS * 12, interval=interval, byweekday=wday)

    it = iter(rule)
    while True:
        yield next(it).date()
 def testPassThruWkst(self):
     newWkst = (calendar.firstweekday() + 2) % 7
     self.failUnlessParseMatches(
         "FREQ=WEEKLY;INTERVAL=2;BYDAY=SU,FR;WKST=%s" %
         (rrule.weekday(newWkst)),
         True,
         {
             'freq': rrule.WEEKLY,
             'interval': 2,
             'byweekday': (rrule.SU, rrule.FR)
         },
         {'wkst': newWkst}  # Test passthru of wkst
     )
Ejemplo n.º 13
0
 def _get_week_days(self):
     """
     :return: tuple of rrule weekdays for this recurrence.
     """
     return tuple(
         rrule.weekday(weekday_index) for weekday_index, weekday in {
             rrule.MO.weekday: self.mon,
             rrule.TU.weekday: self.tue,
             rrule.WE.weekday: self.wed,
             rrule.TH.weekday: self.thu,
             rrule.FR.weekday: self.fri,
             rrule.SA.weekday: self.sat,
             rrule.SU.weekday: self.sun,
         }.items() if weekday)
Ejemplo n.º 14
0
 def get_occurrences(self, start, end):
     """
     Returns start datetimes of occurrences of the event that overlap with [start, end]
     Expects start < end
     :type start: datetime
     :type end: datetime
     :return:
     """
     event_start = datetime.combine(
         self.start_date, self.start_time if self.start_time else time.min)
     event_end = datetime.combine(
         self.end_date, self.end_time if self.end_time else time.max)
     event_span = event_end - event_start
     recurrence = self.recurrence_rule
     if recurrence:
         until = min(
             end,
             datetime.combine(
                 recurrence.end_date if recurrence.end_date else date.max,
                 time.max))
         if recurrence.frequency in (frequency.DAILY, frequency.YEARLY):
             occurrences = rrule(recurrence.frequency,
                                 dtstart=event_start,
                                 interval=recurrence.interval,
                                 until=until)
         elif recurrence.frequency == frequency.WEEKLY:
             occurrences = rrule(recurrence.frequency,
                                 dtstart=event_start,
                                 interval=recurrence.interval,
                                 byweekday=recurrence.weekdays_for_weekly,
                                 until=until)
         else:
             occurrences = rrule(recurrence.frequency,
                                 dtstart=event_start,
                                 interval=recurrence.interval,
                                 byweekday=weekday(
                                     recurrence.weekday_for_monthly,
                                     recurrence.week_for_monthly),
                                 until=until)
         return [
             x for x in occurrences
             if start <= x <= end or start <= x + event_span <= end
         ]
     return [
         event_start
     ] if start <= event_start <= end or start <= event_end <= end else []
Ejemplo n.º 15
0
    def _rrule_parse(self, rule_str, date_start):
        # LUL TODO clean this mess
        data = {}
        day_list = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']

        if 'Z' in rule_str and date_start and not date_start.tzinfo:
            date_start = pytz.utc.localize(date_start)
        rule = rrule.rrulestr(rule_str, dtstart=date_start)

        data['rrule_type'] = freq_to_select(rule._freq)
        data['count'] = rule._count
        data['interval'] = rule._interval
        data['until'] = rule._until
        # Repeat weekly
        if rule._byweekday:
            for weekday in day_list:
                data[weekday] = False  # reset
            for weekday_index in rule._byweekday:
                weekday = rrule.weekday(weekday_index)
                data[weekday_to_field(weekday.weekday)] = True
                data['rrule_type'] = 'weekly'

        # Repeat monthly by nweekday ((weekday, weeknumber), )
        if rule._bynweekday:
            data['weekday'] = day_list[list(rule._bynweekday)[0][0]].upper()
            data['byday'] = str(list(rule._bynweekday)[0][1])
            data['month_by'] = 'day'
            data['rrule_type'] = 'monthly'

        if rule._bymonthday:
            data['day'] = list(rule._bymonthday)[0]
            data['month_by'] = 'date'
            data['rrule_type'] = 'monthly'

        # Repeat yearly but for odoo it's monthly, take same information as monthly but interval is 12 times
        if rule._bymonth:
            data['interval'] *= 12

        if data.get('until'):
            data['end_type'] = 'end_date'
        elif data.get('count'):
            data['end_type'] = 'count'
        else:
            data['end_type'] = 'forever'
        return data
def parse_rrule(rule):
    """
    Parse the given C{rrule}, returning a 3-element C{tuple}:

    element 0: C{true_rep}: A C{boolean}: That indicates if this rule can be
                represented exactly in the UI. In practice, this is used to
                pop up a confirmation dialog before editing.
    element 1: C{canonical}: A C{dict} of keywords you can use to initialize
                a C{dateutil.rrule.rrule}. 
    element 2: C{passthru}: A C{dict} of keywords that the UI ignores, but
                won't result in data loss when you edit. Examples include
                C{'until'}, C{'byhour'}. C{EditRecurrence} includes these
                values in the returned C{dict}.
    """

    true_rep = True
    canonical = {}
    passthru = {}

    if rule._count:
        # We don't support COUNT rules
        true_rep = False

    wkst = rule._wkst
    if wkst != calendar.firstweekday(
    ):  # sic (rrule inserts this automatically)
        passthru['wkst'] = wkst

    for attr in "hour", "minute", "second":
        # rrule creates these automatically, so bypass the automatically
        # set values.
        val = getattr(rule, '_by' + attr, None)
        # default value is a 1-element tuple with value
        # matching _dtstart.
        if val and val != (getattr(rule._dtstart, attr), ):
            passthru['by' + attr] = val

    for attr in 'until', :
        val = getattr(rule, '_' + attr, None)
        if val is not None:
            passthru[attr] = val

    canonical.update(interval=rule._interval)

    # _byweekday: tuple of ints
    # _bynweekday: tuple of (day, n) ints
    # We combine these into a tuple of rrule.weekday objects

    # Only support of BYSETPOS is in the "alternate byweekday rule "below,
    # and we only support a single value here.
    bysetposException = (len(rule._byweekday or
                             ()) == 1 == len(rule._bysetpos or ()))

    byweekday = []

    if rule._bynweekday:
        if len(rule._bynweekday) > 1:
            true_rep = False
        elif rule._bynweekday[0][1] not in (1, 2, 3, 4, -1):
            true_rep = False
        byweekday.extend(rrule.weekday(*t) for t in rule._bynweekday)

    if bysetposException:
        byweekday.append(rrule.weekday(rule._byweekday[0], rule._bysetpos[0]))
    elif rule._byweekday and rule._byweekday != (rule._dtstart.weekday(), ):
        byweekday.extend(rrule.weekday(day) for day in rule._byweekday)

    if byweekday:
        canonical.update(byweekday=tuple(byweekday))

    if (rule._bysetpos and not bysetposException):
        true_rep = False

    if rule._bymonth and rule._bymonth != (rule._dtstart.month, ):
        canonical.update(bymonth=rule._bymonth)

    # rule._bymonthday == days of month counted from start
    # rule._bynmonthday == days of month counted from end (unsupported)
    bymonthday = rule._bymonthday + rule._bynmonthday
    if bymonthday and bymonthday != (rule._dtstart.day, ):
        canonical.update(bymonthday=tuple(sorted(bymonthday)))

    if rule._bynmonthday:
        # We only support -1 for _bynmonthday
        if not all(day == -1 for day in rule._bynmonthday):
            true_rep = False

    # rule._byweekno (unsupported)
    if rule._byweekno:
        true_rep = False
        canonical.update(byweekno=rule._byweekno)

    if rule._byyearday:
        true_rep = False
        canonical.update(byyearday=rule._byyearday)

    canonical.update(freq=rule._freq)

    customKeys = set(canonical.keys()) - set(['freq', 'interval'])
    if rule._freq == rrule.YEARLY:
        if customKeys - set(['bymonth', 'byweekday']):
            true_rep = False
    elif rule._freq == rrule.MONTHLY:
        # For monthly, we support exactly one of bymonthday and
        # byweekday
        if len(customKeys) > 1:
            true_rep = False
        elif customKeys - set(['bymonthday', 'byweekday']):
            true_rep = False
        # Note, not supporting multiple _bynweekday is handled earlier
    elif rule._freq == rrule.WEEKLY:
        if customKeys - set(['byweekday']):
            true_rep = False
    elif rule._freq == rrule.DAILY:
        if customKeys:
            true_rep = False
    else:
        # We don't support HOURLY/MINUTELY/SECONDLY
        true_rep = False

    return true_rep, canonical, passthru
Ejemplo n.º 17
0
 def _get_lang_week_start(self):
     lang = self.env['res.lang']._lang_get(self.env.user.lang)
     week_start = int(
         lang.week_start)  # lang.week_start ranges from '1' to '7'
     return rrule.weekday(week_start -
                          1)  # rrule expects an int from 0 to 6
Ejemplo n.º 18
0
    def _parseBooking(self, booking):
        start = self._date_parse(booking['startdate'])
        # if start.date() != date(2017,12, 11):
        #   continue
        # print(json.dumps(booking, indent=2))
        start_date = datetime.datetime.combine(start, datetime.time(0, 0))
        end = self._date_parse(booking['enddate'])
        duration = end - start
        rules = rruleset()
        repeat_id = int(booking['repeat_id'])
        if repeat_id != 0 and repeat_id != 999:
            repeat_until = self._date_parse(booking['repeat_until'])
            repeat_freq = int(booking['repeat_frequence'])
            # print("Type: %s, Freq: %s, Start: %s, Until: %s" % (repeat_id, repeat_freq, start, repeat_until))
            if repeat_id == 1:  # daily
                rules.rrule(rrule(DAILY, dtstart=start_date, until=repeat_until, interval=repeat_freq))
            if repeat_id == 7:  # weekly
                # print("Start: %s\nUntil: %s\nInterval: %s" % (start, repeat_until, repeat_freq))
                rules.rrule(rrule(WEEKLY, dtstart=start_date, interval=repeat_freq, until=repeat_until))
            elif repeat_id == 31:  # monthly by datetime
                rules.rrule(rrule(MONTHLY, dtstart=start_date, until=repeat_until, interval=repeat_freq))
            elif repeat_id == 32:  # monthly by weekday
                repeat_option_id = int(booking['repeat_option_id']) if booking['repeat_option_id'] else 0
                if repeat_option_id == 6:
                    raise NotImplementedError(
                        "Error: repeat_option_id == 6 not implemented! Booking:\n%s" % json.dumps(booking, indent=2))

                # nthweekOfMonth = (start.day - 1) // 7 + 1
                nthweekOfMonth = repeat_option_id
                # print(nthweekOfMonth)
                rule = rrule(MONTHLY,
                             dtstart=start_date,
                             until=repeat_until,
                             interval=repeat_freq,
                             byweekday=weekday(start.weekday())(+nthweekOfMonth))
                # print(rule)
                rules.rrule(rule)
            elif repeat_id == 365:
                rules.rrule(rrule(YEARLY, dtstart=start_date, until=repeat_until, interval=repeat_freq))
        elif repeat_id in [0, 999]:
            # print("Simple: %s" % start_date)
            rules.rdate(start_date)
        else:
            raise NotImplementedError(
                "Error: Repeat Frequency is not implemented! Booking:\n%s" % json.dumps(booking, indent=2))
            print("Error: Repeat Frequency %s:\n%s" % (repeat_freq, json.dumps(booking, indent=2)))
        if 'additions' in booking and booking['additions']:
            adds = booking['additions']
            for a in adds:
                addition = adds[a]
                add_date = datetime.datetime.combine(self._date_parse(addition['add_date']), datetime.time(0, 0))
                # print("Addition: %s" % add_date)
                rules.rdate(add_date)
        if 'exceptions' in booking and booking['exceptions']:
            # print(booking)
            exceptions = booking['exceptions']
            for exc in exceptions:
                exception = exceptions[exc]

                exc_start = self._date_parse(exception['except_date_start'])
                exc_end = self._date_parse(exception['except_date_end'])
                # print("Exception: %s" % exc_start)
                if exc_start != exc_end:
                    print("Exception has different start and end: %s" % exception)
                rules.exdate(datetime.datetime.combine(exc_start, datetime.time(0, 0)))
        return rules, start, duration
Ejemplo n.º 19
0
def parse_rrule(rule):
    """
    Parse the given C{rrule}, returning a 3-element C{tuple}:

    element 0: C{true_rep}: A C{boolean}: That indicates if this rule can be
                represented exactly in the UI. In practice, this is used to
                pop up a confirmation dialog before editing.
    element 1: C{canonical}: A C{dict} of keywords you can use to initialize
                a C{dateutil.rrule.rrule}. 
    element 2: C{passthru}: A C{dict} of keywords that the UI ignores, but
                won't result in data loss when you edit. Examples include
                C{'until'}, C{'byhour'}. C{EditRecurrence} includes these
                values in the returned C{dict}.
    """
    
    true_rep = True
    canonical = {}
    passthru = {}
    
    if rule._count:
        # We don't support COUNT rules
        true_rep = False
    
    wkst = rule._wkst
    if wkst != calendar.firstweekday(): # sic (rrule inserts this automatically)
        passthru['wkst'] = wkst

    for attr in "hour", "minute", "second":
        # rrule creates these automatically, so bypass the automatically
        # set values.
        val = getattr(rule, '_by' + attr, None)
        # default value is a 1-element tuple with value
        # matching _dtstart.
        if val and val != (getattr(rule._dtstart, attr),):
            passthru['by' + attr] = val

    for attr in 'until',:
        val = getattr(rule, '_' + attr, None)
        if val is not None:
            passthru[attr] = val

    canonical.update(interval=rule._interval)
    

    # _byweekday: tuple of ints
    # _bynweekday: tuple of (day, n) ints
    # We combine these into a tuple of rrule.weekday objects

    # Only support of BYSETPOS is in the "alternate byweekday rule "below,
    # and we only support a single value here.
    bysetposException = (
        len(rule._byweekday or ()) == 1 == len(rule._bysetpos or ()))

    byweekday = []
    
    if rule._bynweekday:
        if len(rule._bynweekday) > 1:
            true_rep = False
        elif rule._bynweekday[0][1] not in (1, 2, 3, 4, -1):
            true_rep = False
        byweekday.extend(rrule.weekday(*t) for t in rule._bynweekday)

    if bysetposException:
        byweekday.append(rrule.weekday(rule._byweekday[0], rule._bysetpos[0]))
    elif rule._byweekday and rule._byweekday != (rule._dtstart.weekday(),):
        byweekday.extend(rrule.weekday(day) for day in rule._byweekday)
        
    if byweekday:
        canonical.update(byweekday=tuple(byweekday))

    if (rule._bysetpos and not bysetposException):
        true_rep = False

    if rule._bymonth and rule._bymonth != (rule._dtstart.month,):
        canonical.update(bymonth=rule._bymonth)

    # rule._bymonthday == days of month counted from start
    # rule._bynmonthday == days of month counted from end (unsupported)
    bymonthday = rule._bymonthday + rule._bynmonthday
    if bymonthday and bymonthday != (rule._dtstart.day,):
        canonical.update(bymonthday=tuple(sorted(bymonthday)))

    if rule._bynmonthday:
        # We only support -1 for _bynmonthday
        if not all(day == -1 for day in rule._bynmonthday):
            true_rep = False

    # rule._byweekno (unsupported)
    if rule._byweekno:
        true_rep = False
        canonical.update(byweekno=rule._byweekno)

    if rule._byyearday:
        true_rep = False
        canonical.update(byyearday=rule._byyearday)

    canonical.update(freq=rule._freq)
    
    customKeys = set(canonical.keys()) - set(['freq', 'interval'])
    if rule._freq == rrule.YEARLY:
        if customKeys - set(['bymonth', 'byweekday']):
            true_rep = False
    elif rule._freq == rrule.MONTHLY:
        # For monthly, we support exactly one of bymonthday and
        # byweekday
        if len(customKeys) > 1:
            true_rep = False
        elif customKeys - set(['bymonthday', 'byweekday']):
             true_rep = False
         # Note, not supporting multiple _bynweekday is handled earlier
    elif rule._freq == rrule.WEEKLY:
        if customKeys - set(['byweekday']):
            true_rep = False
    elif rule._freq == rrule.DAILY:
        if customKeys:
            true_rep = False
    else:
        # We don't support HOURLY/MINUTELY/SECONDLY
        true_rep = False

    return true_rep, canonical, passthru
Ejemplo n.º 20
0
    def do_t_recurs(self, line):
        """Make a task recurs
        t_recurs <id> yearly <dd/mm> <HH:MM>
        t_recurs <id> monthly <dd> <HH:MM>
        t_recurs <id> monthly <first/second/third/last> <mo, tu, we, th, fr, sa, su> <hh:mm>
        t_recurs <id> quarterly <dd> <HH:MM>
        t_recurs <id> quarterly <first/second/third/last> <mo, tu, we, th, fr, sa, su> <hh:mm>
        t_recurs <id> weekly <mo, tu, we, th, fr, sa, su> <hh:mm>
        t_recurs <id> daily <HH:MM>
        t_recurs <id> none (remove recurrence)"""
        tokens = parseutils.simplifySpaces(line).split()
        if len(tokens) < 2:
            raise YokadiException("You should give at least two arguments: <task id> <recurrence>")
        task = self.getTaskFromId(tokens[0])

        # Define recurrence:
        freq = byminute = byhour = byweekday = bymonthday = bymonth = None

        tokens[1] = tokens[1].lower()

        if tokens[1] == "none":
            if task.recurrence:
                self.session.delete(task.recurrence)
                task.recurrence = None
            return
        elif tokens[1] == "daily":
            if len(tokens) != 3:
                raise YokadiException("You should give time for daily task")
            freq = rrule.DAILY
            byhour, byminute = ydateutils.getHourAndMinute(tokens[2])
        elif tokens[1] == "weekly":
            freq = rrule.WEEKLY
            if len(tokens) != 4:
                raise YokadiException("You should give day and time for weekly task")
            byweekday = ydateutils.getWeekDayNumberFromDay(tokens[2].lower())
            byhour, byminute = ydateutils.getHourAndMinute(tokens[3])
        elif tokens[1] in ("monthly", "quarterly"):
            if tokens[1] == "monthly":
                freq = rrule.MONTHLY
            else:
                # quarterly
                freq = rrule.YEARLY
                bymonth = [1, 4, 7, 10]
            if len(tokens) < 4:
                raise YokadiException("You should give day and time for %s task" % (tokens[1],))
            try:
                bymonthday = int(tokens[2])
                byhour, byminute = ydateutils.getHourAndMinute(tokens[3])
            except ValueError:
                POSITION = {"first": 1, "second": 2, "third": 3, "fourth": 4, "last":-1}
                if tokens[2].lower() in list(POSITION.keys()) and len(tokens) == 5:
                    byweekday = rrule.weekday(ydateutils.getWeekDayNumberFromDay(tokens[3].lower()),
                                              POSITION[tokens[2]])
                    byhour, byminute = ydateutils.getHourAndMinute(tokens[4])
                    bymonthday = None  # Default to current day number - need to be blanked
                else:
                    raise YokadiException("Unable to understand date. See help t_recurs for details")
        elif tokens[1] == "yearly":
            freq = rrule.YEARLY
            rDate = ydateutils.parseHumaneDateTime(" ".join(tokens[2:]))
            bymonth = rDate.month
            bymonthday = rDate.day
            byhour = rDate.hour
            byminute = rDate.minute
        else:
            raise YokadiException("Unknown frequency. Available: daily, weekly, monthly and yearly")

        if task.recurrence is None:
            task.recurrence = Recurrence()
        rr = rrule.rrule(freq, byhour=byhour, byminute=byminute, byweekday=byweekday,
                         bymonthday=bymonthday, bymonth=bymonth)
        task.recurrence.setRrule(rr)
        task.dueDate = task.recurrence.getNext()
        self.session.merge(task)
        self.session.commit()
Ejemplo n.º 21
0
 def test_weekday(self):
     w = dateutil_rrule.weekday(5)
     result = self.dumps(w)
     self.assertEqual(json.loads(result), self.weekday())
Ejemplo n.º 22
0
    def get_occurrences(self, start, end):
        """
        Get occurrences of the event that overlap with ``[start, end]``.
        Expects ``start < end``.

        :param start: the begin of the requested interval.
        :type start: ~datetime.datetime

        :param end: the end of the requested interval.
        :type end: ~datetime.datetime

        :return: start datetimes of occurrences of the event that are in the given timeframe
        :rtype: list [ ~datetime.datetime ]
        """
        event_start = datetime.combine(
            self.start_date, self.start_time if self.start_time else time.min
        )
        event_end = datetime.combine(
            self.end_date, self.end_time if self.end_time else time.max
        )
        event_span = event_end - event_start
        recurrence = self.recurrence_rule
        if recurrence is not None:
            until = min(
                end,
                datetime.combine(
                    recurrence.recurrence_end_date
                    if recurrence.recurrence_end_date
                    else date.max,
                    time.max,
                ),
            )
            if recurrence.frequency in (frequency.DAILY, frequency.YEARLY):
                occurrences = rrule(
                    recurrence.frequency,
                    dtstart=event_start,
                    interval=recurrence.interval,
                    until=until,
                )
            elif recurrence.frequency == frequency.WEEKLY:
                occurrences = rrule(
                    recurrence.frequency,
                    dtstart=event_start,
                    interval=recurrence.interval,
                    byweekday=recurrence.weekdays_for_weekly,
                    until=until,
                )
            else:
                occurrences = rrule(
                    recurrence.frequency,
                    dtstart=event_start,
                    interval=recurrence.interval,
                    byweekday=weekday(
                        recurrence.weekday_for_monthly, recurrence.week_for_monthly
                    ),
                    until=until,
                )
            return [
                x
                for x in occurrences
                if start <= x <= end or start <= x + event_span <= end
            ]
        return (
            [event_start]
            if start <= event_start <= end or start <= event_end <= end
            else []
        )
Ejemplo n.º 23
0
    def do_t_recurs(self, line):
        """Make a task recurs
        t_recurs <id> yearly <dd/mm> <HH:MM>
        t_recurs <id> monthly <dd> <HH:MM>
        t_recurs <id> monthly <first/second/third/last> <mo, tu, we, th, fr, sa, su> <hh:mm>
        t_recurs <id> quarterly <dd> <HH:MM>
        t_recurs <id> quarterly <first/second/third/last> <mo, tu, we, th, fr, sa, su> <hh:mm>
        t_recurs <id> weekly <mo, tu, we, th, fr, sa, su> <hh:mm>
        t_recurs <id> daily <HH:MM>
        t_recurs <id> none (remove recurrence)"""
        tokens = parseutils.simplifySpaces(line).split()
        if len(tokens) < 2:
            raise YokadiException(
                "You should give at least two arguments: <task id> <recurrence>"
            )
        task = self.getTaskFromId(tokens[0])

        # Define recurrence:
        freq = byminute = byhour = byweekday = bymonthday = bymonth = None

        tokens[1] = tokens[1].lower()

        if tokens[1] == "none":
            if task.recurrence:
                task.recurrence.destroySelf()
                task.recurrence = None
            return
        elif tokens[1] == "daily":
            if len(tokens) != 3:
                raise YokadiException("You should give time for daily task")
            freq = rrule.DAILY
            byhour, byminute = ydateutils.getHourAndMinute(tokens[2])
        elif tokens[1] == "weekly":
            freq = rrule.WEEKLY
            if len(tokens) != 4:
                raise YokadiException(
                    "You should give day and time for weekly task")
            byweekday = ydateutils.getWeekDayNumberFromDay(tokens[2].lower())
            byhour, byminute = ydateutils.getHourAndMinute(tokens[3])
        elif tokens[1] in ("monthly", "quarterly"):
            if tokens[1] == "monthly":
                freq = rrule.MONTHLY
            else:
                # quarterly
                freq = rrule.YEARLY
                bymonth = [1, 4, 7, 10]
            if len(tokens) < 4:
                raise YokadiException(
                    "You should give day and time for %s task" % (tokens[1], ))
            try:
                bymonthday = int(tokens[2])
                byhour, byminute = ydateutils.getHourAndMinute(tokens[3])
            except ValueError:
                POSITION = {
                    "first": 1,
                    "second": 2,
                    "third": 3,
                    "fourth": 4,
                    "last": -1
                }
                if tokens[2].lower() in POSITION.keys() and len(tokens) == 5:
                    byweekday = rrule.weekday(
                        ydateutils.getWeekDayNumberFromDay(tokens[3].lower()),
                        POSITION[tokens[2]])
                    byhour, byminute = ydateutils.getHourAndMinute(tokens[4])
                    bymonthday = None  # Default to current day number - need to be blanked
                else:
                    raise YokadiException(
                        "Unable to understand date. See help t_recurs for details"
                    )
        elif tokens[1] == "yearly":
            freq = rrule.YEARLY
            rDate = ydateutils.parseHumaneDateTime(" ".join(tokens[2:]))
            bymonth = rDate.month
            bymonthday = rDate.day
            byhour = rDate.hour
            byminute = rDate.minute
        else:
            raise YokadiException(
                "Unknown frequency. Available: daily, weekly, monthly and yearly"
            )

        if task.recurrence is None:
            task.recurrence = Recurrence()
        rr = rrule.rrule(freq,
                         byhour=byhour,
                         byminute=byminute,
                         byweekday=byweekday,
                         bymonthday=bymonthday,
                         bymonth=bymonth)
        task.recurrence.setRrule(rr)
        task.dueDate = task.recurrence.getNext()
Ejemplo n.º 24
0
    def text(self, date_format="%B %d, %Y", time_format="%I:%M %p"):
        """Return a recurrence rule in plain English (or whatever language, once translation
        is supported. :)
        
        `date_format`
        An optional argument that specifies the format to print dates using strftime 
        formatting rules.
        
        `time_format`
        An optional argument that specifies the format to print times using strftime
        formatting rles.
        """
        
        dtstart = self._dtstart # datetime of when each occurrence starts. Defaults to now, down to the second.
        freq = self._freq # when the recurrence recurs, secondly through yearly. Required.
        interval = self._interval # how often the recurrence happens, each time through every nth time. Defaults to 1.
        wkst = self._wkst # Week start day, ie, an int representing which day of the week starts the week, usually Sunday or Monday. Defaults to calendar.firstweekday().
        until = self._until # datetime until which the recurrence continues. Only it or count is set, not both.
        count = self._count # Number of times the event happens before it stops. Only it or until is set, not both.
        tzinfo = self._tzinfo # Time zone information. Defaults to the tzinfo of dtstart.
        bymonth = self._bymonth # Which month a yearly event recurs in.
        byweekno = self._byweekno # Which week number a yearly event recurs in.
        byyearday = self._byyearday # Which day of the year a yearly event recurs in.
        byweekday = self._byweekday # Which weekday an event recurs in.
        bynweekday = self._bynweekday # 
        byeaster = self._byeaster
        bymonthday = self._bymonthday # Relative day of the month
        bynmonthday = self._bynmonthday # Negative relative day of the month
        bysetpos = self._bysetpos # Must be between -366 and -1 or 1 and 366.
        byhour = self._byhour
        byminute = self._byminute
        bysecond = self._bysecond
        # YEARLY needs to have bymonth and bymonthday set
        # MONTHLY needs to have bymonthday set 
        # WEEKLY needs to have byweekday set
        
        text_description = []
        
        if freq == YEARLY:
            pass
        elif freq == MONTHLY:
            
            # Get the interval. "Each", "Every other", "Every third", etc.
            p_interval = rrule2text.INTERVAL[interval-1][1]
            text_description.append(p_interval)

            # bynweekday is a tuple of (weekday, week_in_month) tuples
            for rule_pair in bynweekday:

                # Get the ordinal.
                for ord in rrule2text.ORDINAL:
                    if ord[0] == rule_pair[1]:
                        text_description.append(ord[1])
                        break

                #  Get the weekday name
                p_weekday = weekday(rule_pair[0])
                name = rrule2text.WEEKDAY_MAP[unicode(p_weekday)]
                text_description.append(name)
                
                text_description.append("at")
                
                text_description.append(dtstart.strftime(time_format))
                
                # tack on "and interval" for the next item in the list
                text_description.extend(["and", p_interval])

            # remove the last "and interval" because it's hanging off the end
            # TODO improve this
            text_description = text_description[:-2]
        
        elif freq == WEEKLY:
            pass
        elif freq == DAILY:
            pass
        elif freq == HOURLY:
            pass
        elif freq == MINUTELY:
            pass
        elif freq == SECONDLY:
            pass
        else:
            raise Rrule2textError, "Frequency value of %s is not valid." % freq
        
        if count:
            text_description.append("%s %s" % (int2word(count).rstrip(), "times"))
        elif until:
            text_description.extend(["until", until.strftime(date_format)])
            
        return map(unicode, text_description)
Ejemplo n.º 25
0
def test_to_weekday_from_dateutil_weekday():
    day = weekday(1)

    assert recurrence.to_weekday(day) == recurrence.Weekday(1)
Ejemplo n.º 26
0
def create_recurring_events(start, end, component):
    """
    Unfold a reoccurring events to its occurrances into the given time frame.

    :param start: start of the time frame
    :param end: end of the time frame
    :param component: iCal component
    :return: occurrances of the event
    """    
    start = normalize(component['DTSTART'].dt)
    end = normalize(end)

    rule = component.get('rrule')

    unfolded = []

    first = create_event(component)
    # unfolded.append(first)

    freq = str(rule.get('FREQ')[0])
    last = find_last(rule, freq, end, first)

    if last < start:
        return
    elif end < last:
        limit = end
    else:
        limit = last
    # import pdb; pdb.set_trace()
    logger.debug('summary: %s; freq: %s; start: %s; limit: %s; rule: %s', component['summary'], freq, start, limit, rule)
    kwargs = {}
    if rule.get('BYDAY'):
        byday = [
            getattr(rrule, s) if len(s) == 2 else rrule.weekday(getattr(rrule, s[-2:]).weekday, int(s[:-2]))
            for s in rule['BYDAY']
        ]
        kwargs['byweekday'] = byday
    if rule.get('INTERVAL'):
        kwargs['interval'] = rule['INTERVAL'][0]
    logger.debug('kwargs: %s', kwargs)
    rrule_obj = rrule.rrule(
        getattr(rrule, freq),
        dtstart=start,
        until=limit,
        **kwargs
    )
    rrule_set = rrule.rruleset()
    rrule_set.rrule(rrule_obj)
    if 'EXDATE' in component:
        for exdate in component['EXDATE'].dts:
            rrule_set.exdate(exdate.dt)
    for dt in list(rrule_set):
        logger.debug('dt: %s', dt)
        unfolded.append(first.copy_to(dt))
    return in_range(unfolded, start, end)


    current = first

    if freq == 'YEARLY':
        while True:
            current = current.copy_to(next_year_at(current.start))
            if current.start < limit:
                unfolded.append(current)
            else:
                break
    if freq == 'MONTHLY':
        while True:
            current = current.copy_to(next_month_at(current.start))
            if current.start < limit:
                unfolded.append(current)
            else:
                break
    else:
        if freq == 'DAILY':
            delta = timedelta(days=1)
        elif freq == 'WEEKLY':
            delta = timedelta(days=7)
        else:
            return

        by_day = rule.get('BYDAY')
        if by_day:
            day_deltas = generate_day_deltas_by_weekday(set(by_day))
        else:
            day_deltas = None

        while True:
            if day_deltas is not None:
                delta = timedelta(days=day_deltas.get(current.start.weekday()))
            current = current.copy_to(current.start + delta)
            if current.start < limit:
                unfolded.append(current)
            else:
                break

    return in_range(unfolded, start, end)