def _gen_dtend_rrule(dtstarts, vevent): """Generate an rdate or rrule from a list of dates and add it to the vevent""" interval = Remind._interval(dtstarts) if interval > 0 and interval % 7 == 0: rset = rrule.rruleset() rset.rrule(rrule.rrule(freq=rrule.WEEKLY, interval=interval//7, count=len(dtstarts))) vevent.rruleset = rset elif interval > 1: rset = rrule.rruleset() rset.rrule(rrule.rrule(freq=rrule.DAILY, interval=interval, count=len(dtstarts))) vevent.rruleset = rset elif interval > 0: if isinstance(dtstarts[0], datetime): rset = rrule.rruleset() rset.rrule(rrule.rrule(freq=rrule.DAILY, count=len(dtstarts))) vevent.rruleset = rset else: vevent.add('dtend').value = dtstarts[-1] + timedelta(days=1) else: rset = rrule.rruleset() if isinstance(dtstarts[0], datetime): for dat in dtstarts: rset.rdate(dat) else: for dat in dtstarts: rset.rdate(datetime(dat.year, dat.month, dat.day)) # temporary set dtstart to a different date, so it's not # removed from rset by python-vobject works around bug in # Android: # https://github.com/rfc2822/davdroid/issues/340 vevent.dtstart.value = dtstarts[0] - timedelta(days=1) vevent.rruleset = rset vevent.dtstart.value = dtstarts[0] if not isinstance(dtstarts[0], datetime): vevent.add('dtend').value = dtstarts[0] + timedelta(days=1)
def get_upcoming_event_list(self, timedelta_in_days): now = datetime.now(timezone.utc) end_date = now + timedelta(days=timedelta_in_days) events = [] for component in self.calendar.walk(): if component.name == "VEVENT": summary = component.get('summary') description = component.get('description') dtstart = component.get('dtstart').dt if dtstart > now and dtstart < end_date: events.append(UpcomingEvent(summary, description, dtstart)) elif component.get('RRULE'): rruleset = rrule.rruleset() rruleset.rrule( rrule.rrulestr( component.get('RRULE').to_ical().decode('utf-8'), dtstart=dtstart)) recurring_dates = rruleset.between(now, end_date) if len(recurring_dates) > 0: events.append( UpcomingEvent(summary, description, recurring_dates[0])) return sorted(events, key=lambda event: event.dtstart)
def _calculate_recurring(self, element, recurring_month): rules = rruleset() dtstart = element.get('dtstart').dt if isinstance(dtstart, date): dtstart = datetime.combine(dtstart, time()) dtstart = dtstart.replace(tzinfo=UTC) rrstr = 'RRULE:%s' % element['RRULE'].to_ical().decode() rule = rrulestr(rrstr, dtstart=dtstart) # in some entries, tzinfo is missing if rule._until and rule._until.tzinfo is None: rule._until = rule._until.replace(tzinfo=UTC) rules.rrule(rule) exdates = element.get('exdate') if not isinstance(exdates, list): exdates = [exdates] for exdate in exdates: try: rules.exdate(exdate.dts[0].dt) except AttributeError: pass return rules.between( dtstart, (datetime.now() + relativedelta(months=int(recurring_month))).replace(tzinfo=UTC), inc=True)
def get_rrule(self, dtstart): if self.complex_rule: d = dtstart.date() weekday = weekdays[d.weekday()] n = 1 + (d.day - 1) / 7 start_day, days_in_month = calendar.monthrange(d.year, d.month) days_from_end = days_in_month - d.day minus_n = -1 - (days_from_end / 7) cr = ( self.complex_rule.replace("%date%", dtstart.strftime("%Y%m%d")) .replace("%day%", dtstart.strftime("%d")) .replace("%month%", dtstart.strftime("%m")) .replace("%year%", dtstart.strftime("%Y")) .replace("%time%", dtstart.strftime("%H%M%S")) .replace("%datetime%", dtstart.strftime("%Y%m%dT%H%M%S")) .replace("%nthday%", "%s%s" % (n, weekday)) .replace("%-nthday%", "%s%s" % (minus_n, weekday)) ) try: return rrule.rrulestr(str(cr), dtstart=dtstart) except ValueError: # eg. unsupported property pass params = self.get_params() frequency = "rrule.%s" % self.frequency simple_rule = rrule.rrule(eval(frequency), dtstart=dtstart, **params) rs = rrule.rruleset() rs.rrule(simple_rule) return rs
def set_biz_calendar(): #hk holidays holidays = [ str2datetime('20150903'), str2datetime('20150928'), str2datetime('20151225'), str2datetime('20151226'), str2datetime('20150701'), str2datetime('20160101'), str2datetime('20160208'), str2datetime('20160209'), str2datetime('20160210'), str2datetime('20160325'), str2datetime('20160326'), str2datetime('20160328'), str2datetime('20160404'), str2datetime('20160502') ] r = rrule.rrule( rrule.DAILY, byweekday=[rrule.MO, rrule.TU, rrule.WE, rrule.TH, rrule.FR], dtstart=str2datetime('20151201')) rs = rrule.rruleset() rs.rrule(r) for exdate in holidays: rs.exdate(exdate) return rs
def __init__(self, event): self.event = event self.start = self.original_start = event["DTSTART"].dt self.end = self.original_end = self._get_event_end() self.exdates = [] self.exdates_utc = set() exdates = event.get("EXDATE", []) for exdates in ((exdates,) if not isinstance(exdates, list) else exdates): for exdate in exdates.dts: self.exdates.append(exdate.dt) self.exdates_utc.add(self._unify_exdate(exdate.dt)) self.rdates = [] rdates = event.get("RDATE", []) for rdates in ((rdates,) if not isinstance(rdates, list) else rdates): for rdate in rdates.dts: self.rdates.append(rdate.dt) self.make_all_dates_comparable() self.duration = self.end - self.start self.rule = rule = rruleset(cache=True) _rule = event.get("RRULE", None) if _rule: self.rrule = self.create_rule_with_start(_rule.to_ical().decode()) rule.rrule(self.rrule) else: self.rrule = None for exdate in self.exdates: rule.exdate(exdate) for rdate in self.rdates: rule.rdate(rdate) rule.rdate(self.start)
def get_due_date(self, now=None, periods=None): if now is None: now = datetime.now() if self.unit == 'hour': delta = timedelta(hours=self.length) elif self.unit == 'day': delta = timedelta(days=self.length) else: delta = None if self.due_at == 'period_end': start_date = now if delta: start_date += delta if self.unit == 'day': start_date = start_date.date() end_dates = rruleset() for period in periods: end_dates.rrule(period.get_end_timestamps(start_date)) if self.unit == 'hour' or self.unit == 'day': return end_dates[0] elif self.unit == 'period': length = self.length if (self.length > 0 and not any(period.is_during_period(now) for period in periods)): length -= 1 return end_dates[length] else: if self.unit == 'hour' or self.unit == 'day': return now + delta
def testTimeSequenceCalendar(self): from dateutil import rrule #import pdb interval = relativedelta(months=1, days=2, hours=3, minutes=13, seconds=27) n = 100 timeseq1=map(ticks,[increment(self.stime1,interval,i) \ for i in range(n)]) timeseq2 = time_sequence(self.stime1, interval, n) for t1, t2 in zip(timeseq1, timeseq2): self.assertEqual(t1, t2) test_cases = [("years", 1, rrule.YEARLY), ("months", 1, rrule.MONTHLY), ("days", 7, rrule.WEEKLY), ("days", 1, rrule.DAILY), ("hours", 1, rrule.HOURLY), ("minutes", 1, rrule.MINUTELY), ("seconds", 1, rrule.SECONDLY)] for (argname, argval, frequency) in test_cases: interval = relativedelta() setattr(interval, argname, argval) n = 100 set = rrule.rruleset() set.rrule(rrule.rrule(frequency, dtstart=self.stime1, count=n)) set.rdate(self.stime1) timeseq1 = list(set) timeseq1 = map(ticks, timeseq1) timeseq2 = time_sequence(self.stime1, interval, n) for t1, t2 in zip(timeseq1, timeseq2): self.assertEqual(t1, t2)
def _expand_rrule_all_day(rrule: str, start: date, exclusions: Iterable, start_at: datetime, end_at: datetime) -> Iterable[date]: """Expand an rrule for all-day events. To my mind, these events cannot have changes, just exclusions, because changes only affect the time, which doesn't exist for all-day events. """ rules = rruleset() rules.rrule(rrulestr(rrule, dtstart=start, ignoretz=True)) # add exclusions if exclusions: for xdate in exclusions: rules.exdate(datetime.combine( xdate.dts[0].dt, datetime.min.time())) dates = [] # reduce start and end to datetimes without timezone that just represent a # date at midnight. for candidate in rules.between( datetime.combine(start_at.date(), datetime.min.time()), datetime.combine(end_at.date(), datetime.min.time()), inc=True): dates.append(candidate.date()) return dates
def _recurring_component_to_events(component): """ Given an icalendar component with an "RRULE" Return a list of events as dictionaries """ rrule_as_str = component.get('rrule').to_ical() recur_rule = rrule.rrulestr(rrule_as_str, dtstart=ensure_tzaware(component.decoded('dtstart'))) recur_set = rrule.rruleset() recur_set.rrule(recur_rule) if 'exdate' in component: lines = component.decoded('exdate') if not hasattr(lines, '__iter__'): lines = [lines] for exdate_line in lines: for exdate in exdate_line.dts: recur_set.exdate(ensure_tzaware(exdate.dt)) # get list of events in MAX_FUTURE days utcnow = now() later = utcnow + datetime.timedelta(days=MAX_FUTURE) start_times = recur_set.between(utcnow, later) # build list of events event_length = component.decoded('dtend') - component.decoded('dtstart') events = [] for start in start_times: events.append({ 'start': start, 'end': start + event_length, 'summary': component.decoded('summary'), 'uid': component.decoded('uid'), 'last_modified': component.decoded('last-modified'), }) return events
def get_early_closes(start, end): # TSX closed at 1:00 PM on december 24th. start = canonicalize_datetime(start) end = canonicalize_datetime(end) start = max(start, datetime(1993, 1, 1, tzinfo=pytz.utc)) end = max(end, datetime(1993, 1, 1, tzinfo=pytz.utc)) # Not included here are early closes prior to 1993 # or unplanned early closes early_close_rules = [] christmas_eve = rrule.rrule( rrule.MONTHLY, bymonth=12, bymonthday=24, byweekday=(rrule.MO, rrule.TU, rrule.WE, rrule.TH, rrule.FR), cache=True, dtstart=start, until=end ) early_close_rules.append(christmas_eve) early_close_ruleset = rrule.rruleset() for rule in early_close_rules: early_close_ruleset.rrule(rule) early_closes = early_close_ruleset.between(start, end, inc=True) early_closes.sort() return pd.DatetimeIndex(early_closes)
def calculate_rrule_exclusions(start_date, end_date, exclusion_commands, settings): exclusion_ruleset = rruleset() exclusion_types = exclusion_commands.exclusionList for exclusion_type in exclusion_types: if hasattr(exclusion_type, "exclusionRange"): from_date, _ = convert_date_time(exclusion_type.exclusionRange.fromDateTime, settings) to_date, _ = convert_date_time(exclusion_type.exclusionRange.toDateTime, settings) exclusion_ruleset.rrule(rrule(freq=DAILY, dtstart=from_date, until=to_date)) elif hasattr(exclusion_type, "exclusionDateTime"): real_date, _ = convert_date_time(exclusion_type.exclusionDateTime, settings) exclusion_ruleset.rrule(rrule(freq=DAILY, dtstart=real_date, until=real_date)) elif hasattr(exclusion_type, "exclusionMacro"): macro_value = exclusion_type.exclusionMacro exclusion_rule = EXCLUSION_MAP[macro_value]['rule'](start=start_date, end=end_date) exclusion_ruleset.rrule(exclusion_rule) else: # in that case, I have no idea what this is (the parser should have caught it) so just # raise an error or something raise UnknownExclusionTypeError matched_dates = list(exclusion_ruleset.between(after=start_date, before=end_date, inc=True)) return len(matched_dates)
def do_timespans(command, settings): date_time, output_format = convert_date_time(command.dateTime, settings) # Note the very first date in case there is an exclusion rule first_date_time = date_time for operand in command.operandList: date_time = delta_arithmetic(date_time, operand) last_date_time = date_time # Make sure the dates are the right way around, or the # following functions will not work correctly. first_date_time, last_date_time = later_date_last(first_date_time, last_date_time) if hasattr(command, "exclusionCommands"): rules = rruleset() exclusion_rules = build_exclusion_list(command, first_date_time, last_date_time, settings) for rule in exclusion_rules: rules.rrule(rule) days_to_exclude = len(rules.between(first_date_time, last_date_time, True)) operand = relativedelta(days=days_to_exclude) date_time += operand return date_time.strftime(output_format)
def next_working_date(date): from dateutil import rrule holidays = [ datetime.date(2012, 5, 1,), datetime.date(2012, 6, 1,), # ... ] # Create a rule to recur every weekday starting today r = rrule.rrule(rrule.DAILY, byweekday=[rrule.MO, rrule.TU, rrule.WE, rrule.TH, rrule.FR], dtstart=datetime.date.today()) # Create a rruleset rs = rrule.rruleset() # Attach our rrule to it rs.rrule(r) # Add holidays as exclusion days for exdate in holidays: rs.exdate(exdate) return (rs[0])
def test_timezone_serializing(self): """ Serializing with timezones test """ tzs = dateutil.tz.tzical("test_files/timezones.ics") pacific = tzs.get('US/Pacific') cal = base.Component('VCALENDAR') cal.setBehavior(icalendar.VCalendar2_0) ev = cal.add('vevent') ev.add('dtstart').value = datetime.datetime(2005, 10, 12, 9, tzinfo=pacific) evruleset = rruleset() evruleset.rrule( rrule(WEEKLY, interval=2, byweekday=[2, 4], until=datetime.datetime(2005, 12, 15, 9))) evruleset.rrule(rrule(MONTHLY, bymonthday=[-1, -5])) evruleset.exdate(datetime.datetime(2005, 10, 14, 9, tzinfo=pacific)) ev.rruleset = evruleset ev.add('duration').value = datetime.timedelta(hours=1) # breaking date? #self.assertEqual( # cal.serialize().replace('\r\n', '\n'), # """BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//PYVOBJECT//NONSGML Version 1//EN\nBEGIN:VTIMEZONE\nTZID:US/Pacific\nBEGIN:STANDARD\nDTSTART:20001029T020000\nRRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\nTZNAME:PST\nTZOFFSETFROM:-0700\nTZOFFSETTO:-0800\nEND:STANDARD\nBEGIN:DAYLIGHT\nDTSTART:20000402T020000\nRRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4\nTZNAME:PDT\nTZOFFSETFROM:-0800\nTZOFFSETTO:-0700\nEND:DAYLIGHT\nEND:VTIMEZONE\nBEGIN:VEVENT\nUID:20150108T142459Z - 64333@testing-worker-linux-12-2-29839-linux-6-46319\n358\nDTSTART;TZID=US/Pacific:20051012T090000\nDURATION:PT1H\nEXDATE;TZID=US/Pacific:20051014T090000\nRRULE:FREQ=WEEKLY;BYDAY=WE,FR;INTERVAL=2;UNTIL=20051215T090000\nRRULE:FREQ=MONTHLY;BYMONTHDAY=-5,-1\nEND:VEVENT\nEND:VCALENDAR\n""" #) apple = tzs.get('America/Montreal') ev.dtstart.value = datetime.datetime(2005, 10, 12, 9, tzinfo=apple)
def occurences(self): from dateutil import rrule r = rrule.rrule(rrule.WEEKLY, dtstart=self.dt_start, until=self.dt_until) ruleset = rrule.rruleset() ruleset.rrule(r) return [Occurence(stamp, self) for stamp in ruleset]
def update_buffer(self): """Update the 2-year date buffer.""" if not self.recur_rule: return frequency = getattr(rrule, self.recur_rule.get_frequency_display().upper()) today = datetime.datetime.today() two_years_hence = today + datetime.timedelta(731) until = self.recur_rule.until or two_years_hence recur = rrule.rrule(frequency, dtstart=self.time, interval=self.recur_rule.interval, until=until) recur_set = rrule.rruleset() recur_set.rrule(recur) for exclusion in self.recur_rule.exclusion_set.all(): recur_set.exdate(exclusion.date) existing_tasks = Task.objects.filter(recur_rule=self.recur_rule) existing_dates = [task.time for task in existing_tasks] for task_date in recur_set: # don't re-create existing tasks if task_date in existing_dates: continue task = Task(job=self.job, time=task_date, hours=self.hours, member=self.member, account=self.account, recur_rule=self.recur_rule) task.save()
def get_next_business_day( from_date: datetime.datetime, until_date: datetime.datetime, time_limit: Optional[datetime.time] = None, reverse: bool = False, ) -> datetime.date: rs = rrule.rruleset() weekdays = [rrule.MO, rrule.TU, rrule.WE, rrule.TH, rrule.FR] weekenddays = (rrule.SA, rrule.SU) rs.rrule( rrule.rrule( rrule.DAILY, dtstart=from_date, until=until_date, byweekday=weekdays ) ) rs.exrule( rrule.rrule( rrule.WEEKLY, dtstart=from_date, until=until_date, byweekday=weekenddays ) ) rs = [rule.date() for rule in rs] # type: ignore holidays_repository = HolidaysJsonRepository() holidays = holidays_repository.get_holidays(from_date.date(), until_date.date()) rs = list(filter(lambda date: date not in holidays, rs)) # type: ignore next_business_day = rs[0] if not reverse else rs[-1] if from_date.date() in rs and time_limit and from_date.time() >= time_limit: next_business_day = rs[1] if not reverse else rs[-2] return next_business_day
def rruleset(self): weekdays = [] if self.monday: weekdays.append(MO) if self.tuesday: weekdays.append(TU) if self.wednesday: weekdays.append(WE) if self.thursday: weekdays.append(TH) if self.friday: weekdays.append(FR) if self.saturday: weekdays.append(SA) if self.sunday: weekdays.append(SU) rset = rruleset() dfrom = datetime.combine(self.from_date, datetime.min.time()).replace(tzinfo=tzutc()) dto = datetime.combine(self.to_date, datetime.max.time()).replace(tzinfo=tzutc()) rset.rrule(rrule(WEEKLY, dtstart=dfrom, until=dto, byweekday=weekdays)) today = datetime.today() for d in DayOff.objects.filter(date__year=today.year): date = datetime.combine(d.date, datetime.min.time()).replace(tzinfo=tzutc()) if self.days_off: rset.rdate(date) else: rset.exdate(date) return rset
def save(self, *args, **kwargs): current_zone = timezone.get_default_timezone() # Set final date to the end, for one off events self.final_date = self.end # But find the last recurring event if possible if self.recurringevent_set.all(): last_date = None # Recurring, find the last date for i in self.recurringevent_set.all(): event_ruleset = rrule.rruleset() event_ruleset.rrule(i.rrule()) # Add in any exclusions for j in self.recurringeventexclusion_set.all(): event_ruleset.exdate(timezone.make_naive(j.date, current_zone)) try: last_recurring_date = event_ruleset[-1] if last_date is None or last_recurring_date > last_date: last_date = last_recurring_date except IndexError: pass if last_date: self.final_date = timezone.make_aware(last_date, current_zone) super(Event, self).save(*args, **kwargs)
def holidays(a=datetime.date.today(), b=datetime.date.today() + datetime.timedelta(days=365)): rs = rrule.rruleset() # Include all potential holiday observances rs.rrule( rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth=12, bymonthday=31, byweekday=rrule.FR)) # New Years Day rs.rrule( rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth=1, bymonthday=1)) # New Years Day rs.rrule( rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth=1, bymonthday=2, byweekday=rrule.MO)) # New Years Day # rs.rrule(rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth= 1, byweekday= rrule.MO(3))) # Martin Luther King Day # rs.rrule(rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth= 2, byweekday= rrule.MO(3))) # Washington's Birthday # rs.rrule(rrule.rrule(rrule.YEARLY, dtstart=a, until=b, byeaster= -2)) # Good Friday # rs.rrule(rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth= 5, byweekday= rrule.MO(-1))) # Memorial Day # rs.rrule(rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth= 7, bymonthday= 3, byweekday=rrule.FR)) # Independence Day # rs.rrule(rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth= 7, bymonthday= 4)) # Independence Day # rs.rrule(rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth= 7, bymonthday= 5, byweekday=rrule.MO)) # Independence Day # rs.rrule(rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth= 9, byweekday= rrule.MO(1))) # Labor Day # rs.rrule(rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth=11, byweekday= rrule.TH(4))) # Thanksgiving Day rs.rrule( rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth=12, bymonthday=24, byweekday=rrule.FR)) # Christmas rs.rrule( rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth=12, bymonthday=25)) # Christmas rs.rrule( rrule.rrule(rrule.YEARLY, dtstart=a, until=b, bymonth=12, bymonthday=26, byweekday=rrule.MO)) # Christmas # Exclude potential holidays that fall on weekends rs.exrule( rrule.rrule(rrule.WEEKLY, dtstart=a, until=b, byweekday=(rrule.SA, rrule.SU))) return rs
def _recurring_component_to_events(component): """ Given an icalendar component with an "RRULE" Return a list of events as dictionaries """ rrule_as_str = component.get('rrule').to_ical() recur_rule = rrule.rrulestr(rrule_as_str, dtstart=component.decoded('dtstart')) recur_set = rrule.rruleset() recur_set.rrule(recur_rule) if 'exdate' in component: for exdate_line in component.decoded('exdate'): for exdate in exdate_line.dts: recur_set.exdate(exdate.dt) # get list of events in MAX_FUTURE days utcnow = now() later = utcnow + datetime.timedelta(days=MAX_FUTURE) start_times = recur_set.between(utcnow, later) # build list of events event_length = component.decoded('dtend') - component.decoded('dtstart') events = [] for start in start_times: events.append({ 'start': start, 'end': start + event_length, 'summary': component.decoded('summary'), 'uid': component.decoded('uid'), 'last_modified': component.decoded('last-modified'), }) return events
def get_rrule(self, dtstart): if self.complex_rule: d = dtstart.date() weekday = weekdays[d.weekday()] n = 1 + (d.day - 1) / 7 start_day, days_in_month = calendar.monthrange(d.year, d.month) days_from_end = days_in_month - d.day minus_n = -1 - (days_from_end / 7) cr = self.complex_rule \ .replace("%date%", dtstart.strftime("%Y%m%d")) \ .replace("%day%", dtstart.strftime("%d")) \ .replace("%month%", dtstart.strftime("%m")) \ .replace("%year%", dtstart.strftime("%Y")) \ .replace("%time%", dtstart.strftime("%H%M%S")) \ .replace("%datetime%", dtstart.strftime("%Y%m%dT%H%M%S")) \ .replace("%nthday%", "%s%s" % (n, weekday)) \ .replace("%-nthday%", "%s%s" % (minus_n, weekday)) try: return rrule.rrulestr(str(cr), dtstart=dtstart) except ValueError: # eg. unsupported property pass params = self.get_params() frequency = 'rrule.%s' % self.frequency simple_rule = rrule.rrule(eval(frequency), dtstart=dtstart, **params) rs = rrule.rruleset() rs.rrule(simple_rule) return rs
def createDateUtilFromRule(self, dtstart, ignoreIsCount=True, convertFloating=False, ignoreShortFrequency=True): """Return an appropriate dateutil.rrule.rruleset. @param dtstart: The start time for the recurrence rule @type dtstart: C{datetime} @param ignoreIsCount: Whether the isCount flag should be used to convert until endtimes to a count. Converting to count takes extra cycles and is only necessary when the rule is going to be serialized @type ignoreIsCount: C{bool} @param convertFloating: Whether or not to allow view.tzinfo.floating in datetimes of the rruleset. If C{True}, naive datetimes are used instead. This is needed for exporting floating events to icalendar format. @type convertFloating: C{bool} @param ignoreShortFrequency: If ignoreShortFrequency is True, replace hourly or more frequent rules with a single RDATE matching dtstart, so as to avoid wasting millions of cycles on nonsensical recurrence rules. @type ignoreShortFrequency: C{bool} @rtype: C{dateutil.rrule.rruleset} """ view = self.itsView args = (ignoreIsCount, convertFloating) ruleset = rruleset() for rtype in 'rrule', 'exrule': for rule in getattr(self, rtype + 's', []): if ignoreShortFrequency and rule.freq in SHORT_FREQUENCIES: # too-frequent rule, as Admiral Ackbar said, "IT'S A TRAP!" ruleset.rdate(dtstart) return ruleset rule_adder = getattr(ruleset, rtype) rule_adder(rule.createDateUtilFromRule(dtstart, *args)) for datetype in 'rdate', 'exdate': for date in getattr(self, datetype + 's', []): if convertFloating and date.tzinfo == view.tzinfo.floating: date = date.replace(tzinfo=None) else: date = coerceTimeZone(view, date, dtstart.tzinfo) getattr(ruleset, datetype)(date) if (ignoreIsCount and not getattr(self, 'rrules', []) and getattr(self, 'rdates', [])): # no rrule, but there are RDATEs, create an RDATE for dtstart, or it # won't appear to be part of the rule ruleset.rdate(dtstart) return ruleset
def test_timezone_serializing(): """ Serializing with timezones test """ tzs = dateutil.tz.tzical("test_files/timezones.ics") pacific = tzs.get('US/Pacific') cal = base.Component('VCALENDAR') cal.setBehavior(icalendar.VCalendar2_0) ev = cal.add('vevent') ev.add('dtstart').value = datetime.datetime(2005, 10, 12, 9, tzinfo=pacific) evruleset = rruleset() evruleset.rrule( rrule(WEEKLY, interval=2, byweekday=[2, 4], until=datetime.datetime(2005, 12, 15, 9))) evruleset.rrule(rrule(MONTHLY, bymonthday=[-1, -5])) evruleset.exdate(datetime.datetime(2005, 10, 14, 9, tzinfo=pacific)) ev.rruleset = evruleset ev.add('duration').value = datetime.timedelta(hours=1) apple = tzs.get('America/Montreal') ev.dtstart.value = datetime.datetime(2005, 10, 12, 9, tzinfo=apple)
def get_due_date(self, now=None, periods=None): if now is None: now = datetime.now() if self.unit == 'hour': delta = timedelta(hours=self.length) elif self.unit == 'day': delta = timedelta(days=self.length) else: delta = None if self.due_at == 'period_end': start_date = now if delta: start_date += delta end_dates = rruleset() for period in periods: end_dates.rrule(period.get_end_timestamps(start_date)) if self.unit == 'hour' or self.unit == 'day': return end_dates[0] elif self.unit == 'period': return end_dates[self.length] else: if self.unit == 'hour' or self.unit == 'day': return now + delta
def get_early_closes(start, end): # TSX closed at 1:00 PM on december 24th. start = canonicalize_datetime(start) end = canonicalize_datetime(end) start = max(start, datetime(1993, 1, 1, tzinfo=pytz.utc)) end = max(end, datetime(1993, 1, 1, tzinfo=pytz.utc)) # Not included here are early closes prior to 1993 # or unplanned early closes early_close_rules = [] christmas_eve = rrule.rrule(rrule.MONTHLY, bymonth=12, bymonthday=24, byweekday=(rrule.MO, rrule.TU, rrule.WE, rrule.TH, rrule.FR), cache=True, dtstart=start, until=end) early_close_rules.append(christmas_eve) early_close_ruleset = rrule.rruleset() for rule in early_close_rules: early_close_ruleset.rrule(rule) early_closes = early_close_ruleset.between(start, end, inc=True) early_closes.sort() return pd.DatetimeIndex(early_closes)
def test_timezone_serializing(self): """ Serializing with timezones test """ tzs = dateutil.tz.tzical("test_files/timezones.ics") pacific = tzs.get('US/Pacific') cal = base.Component('VCALENDAR') cal.setBehavior(icalendar.VCalendar2_0) ev = cal.add('vevent') ev.add('dtstart').value = datetime.datetime(2005, 10, 12, 9, tzinfo = pacific) evruleset = rruleset() evruleset.rrule(rrule(WEEKLY, interval=2, byweekday=[2,4], until=datetime.datetime(2005, 12, 15, 9))) evruleset.rrule(rrule(MONTHLY, bymonthday=[-1,-5])) evruleset.exdate(datetime.datetime(2005, 10, 14, 9, tzinfo = pacific)) ev.rruleset = evruleset ev.add('duration').value = datetime.timedelta(hours=1) # breaking date? #self.assertEqual( # cal.serialize().replace('\r\n', '\n'), # """BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//PYVOBJECT//NONSGML Version 1//EN\nBEGIN:VTIMEZONE\nTZID:US/Pacific\nBEGIN:STANDARD\nDTSTART:20001029T020000\nRRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\nTZNAME:PST\nTZOFFSETFROM:-0700\nTZOFFSETTO:-0800\nEND:STANDARD\nBEGIN:DAYLIGHT\nDTSTART:20000402T020000\nRRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4\nTZNAME:PDT\nTZOFFSETFROM:-0800\nTZOFFSETTO:-0700\nEND:DAYLIGHT\nEND:VTIMEZONE\nBEGIN:VEVENT\nUID:20150108T142459Z - 64333@testing-worker-linux-12-2-29839-linux-6-46319\n358\nDTSTART;TZID=US/Pacific:20051012T090000\nDURATION:PT1H\nEXDATE;TZID=US/Pacific:20051014T090000\nRRULE:FREQ=WEEKLY;BYDAY=WE,FR;INTERVAL=2;UNTIL=20051215T090000\nRRULE:FREQ=MONTHLY;BYMONTHDAY=-5,-1\nEND:VEVENT\nEND:VCALENDAR\n""" #) apple = tzs.get('America/Montreal') ev.dtstart.value = datetime.datetime(2005, 10, 12, 9, tzinfo = apple)
def _get_rruleset(self): self.ensure_one() ruleset = rruleset() if self.state != 'progress': return ruleset # set next_date which is used as the rrule 'dtstart' parameter next_date = self.start_date last_order = self.env['fsm.order'].search( [('fsm_recurring_id', '=', self.id), ('stage_id', '!=', self.env.ref('fieldservice.fsm_stage_cancelled').id)], offset=0, limit=1, order='scheduled_date_start desc') if last_order: next_date = last_order.scheduled_date_start # set thru_date to use as rrule 'until' parameter days_ahead = self.fsm_frequency_set_id.schedule_days request_thru_date = datetime.now() + relativedelta(days=+days_ahead) if self.end_date and (self.end_date < request_thru_date): thru_date = self.end_date else: thru_date = request_thru_date # use variables to calulate and return the rruleset object ruleset = self.fsm_frequency_set_id._get_rruleset(dtstart=next_date, until=thru_date) return ruleset
def _rule_set(self, dtstart): rule = rrule.rrulestr(self.repeat_rule, dtstart=dtstart) rule_set = rrule.rruleset() rule_set.rrule(rule) for exdate in self.exception_dates: rule_set.exdate(exdate) return rule_set
def get_events_from_rrule(ical_event, event_template, start_date, end_date): events = [] ical_rrule = ical_event.get('rrule') ical_rrule_str = ical_rrule.to_ical().decode('utf-8') rrule = rrulestr(ical_rrule_str, ignoretz=True, dtstart=start_date.replace(tzinfo=None)) ruleset = rruleset() ruleset.rrule(rrule) exdates = get_exdates(ical_event) for exdate in exdates: for exdate_date in exdate.dts: ruleset.exdate(exdate_date.dt.replace(tzinfo=None)) after = datetime.utcnow() - timedelta(**INTO_PAST) before = datetime.utcnow() + timedelta(**INTO_FUTURE) rrule_instances = list(ruleset.between(after, before)) for num, rrule_instance in enumerate(rrule_instances, start=1): event = copy(event_template) event['uid'] = "{}-{}".format(event_template['uid'], num) event['start'] = berlin.localize(rrule_instance).isoformat() if not event["allDay"]: instance_end_date = datetime(rrule_instance.year, rrule_instance.month, rrule_instance.day, end_date.hour, end_date.minute, end_date.second) event["end"] = berlin.localize(instance_end_date).isoformat() print(repr(event)) events.append(event) return events
def setRuleFromDateUtil(self, ruleSetOrRule): """Extract rules and dates from ruleSetOrRule, set them in self. If a dateutil.rrule.rrule is passed in instead of an rruleset, treat it as the new rruleset. """ if isinstance(ruleSetOrRule, rrule): set = rruleset() set.rrule(ruleSetOrRule) ruleSetOrRule = set elif not isinstance(ruleSetOrRule, rruleset): raise TypeError, "ruleSetOrRule must be an rrule or rruleset" for rtype in 'rrule', 'exrule': rules = getattr(ruleSetOrRule, '_' + rtype, []) if rules is None: rules = [] itemlist = [] for rule in rules: ruleItem = RecurrenceRule(parent=self) ruleItem.setRuleFromDateUtil(rule) itemlist.append(ruleItem) setattr(self, rtype + 's', itemlist) for typ in 'rdate', 'exdate': # While most dates are naive, strip tzinfo off naive = [stripTZ(e) for e in getattr(ruleSetOrRule, '_' + typ, [])] setattr(self, typ + 's', naive)
def get_number_of_hours_between_dates( d1, d2, skip_weekends=True, list_public_holidays=False, hours_range=range(0,23), granularity=12 ): def convert_days_from_hours(hours, granularity, hours_per_day): return int(hours/granularity)*granularity/hours_per_day rules = rrule.rruleset() byweekday_list = [rrule.MO, rrule.TU, rrule.WE, rrule.TH, rrule.FR] if not skip_weekends: byweekday_list.extend([rrule.SA, rrule.SU]) rules.rrule( rrule.rrule( freq=rrule.HOURLY, byweekday=byweekday_list, byhour=hours_range, dtstart=d1, until=d2, ) ) if list_public_holidays: for holiday in list_public_holidays: s1 = datetime(holiday.year, holiday.month, holiday.day, 0, 0, 0) s2 = datetime(holiday.year, holiday.month, holiday.day, 23, 59, 59) rules.exrule( rrule.rrule( rrule.HOURLY, dtstart=s1, until=s2 ) ) dates = defaultdict(int) for r in list(rules): dates[r.date()] += 1 return {k: convert_days_from_hours(v, granularity, len(hours_range)) for k, v in dates.items()}
def parse_rrule(component, tz=UTC): """ Extract a dateutil.rrule object from an icalendar component. Also includes the component's dtstart and exdate properties. The rdate and exrule properties are not yet supported. :param component: icalendar component :param tz: timezone for DST handling :return: extracted rrule or rruleset """ if component.get('rrule'): # component['rrule'] can be both a scalar and a list rrules = component['rrule'] if not isinstance(rrules, list): rrules = [rrules] # Since DTSTART are always made timezone aware, UNTIL with no tzinfo # must be converted to UTC. for rule in rrules: until = rule.get("until") for idx, dt in enumerate(until or []): if not hasattr(dt, 'tzinfo'): until[idx] = normalize(normalize(dt, tz=tz), tz=UTC) # Parse the rrules, might return a rruleset instance, instead of rrule rule = rrulestr('\n'.join(x.to_ical().decode() for x in rrules), dtstart=normalize(component['dtstart'].dt, tz=tz)) if component.get('exdate'): # Make sure, to work with a rruleset if isinstance(rule, rrule): rules = rruleset() rules.rrule(rule) rule = rules # Add exdates to the rruleset for exd in extract_exdates(component): rule.exdate(exd) #TODO: What about rdates and exrules? # You really want an rrule for a component without rrule? Here you are. else: rule = rruleset() rule.rdate(normalize(component['dtstart'].dt, tz=tz)) return rule
def convert_rdates(dates: List[datetime]): rrules = rruleset() dates.sort() rrules.rrule( rrule(YEARLY, count=1, dtstart=dates.pop(0).replace(tzinfo=None))) for dt in dates: rrules.rdate(dt.replace(tzinfo=None)) return [rrules]
def _default_ruleset(): '''Return a datetime.rrule.rruleset object that excludes weekends.''' dates = rrule.rruleset() # exclude weekends dates.rrule(rrule.rrule(rrule.DAILY, byweekday=( rrule.MO, rrule.TU, rrule.WE, rrule.TH, rrule.FR, ))) return dates
def NYSE_tradingdays(a, b): rs = rrule.rruleset() rs.rrule(rrule.rrule(rrule.DAILY, dtstart=a, until=b)) # Exclude weekends and holidays rs.exrule( rrule.rrule(rrule.WEEKLY, dtstart=a, byweekday=(rrule.SA, rrule.SU))) rs.exrule(NYSE_holidays(a, b)) return rs
def init_rruleset(): rr = rruleset() rr.rrule(rrule(DAILY, byweekday=(MO,TU,WE,TH,FR), dtstart=datetime.datetime(2010,1,1))) for h in holidays: rr.exdate(h) return rr
def rruleset(self, dtstart): set_ = rruleset(**self._rruleset()) for rule in self.rules: if not rule.exclusive: set_.rrule(rule.rrule(dtstart)) else: set_.exrule(rule.rrule(dtstart)) return set_
def get_events(url): req = urllib.request.Request(url) res = urllib.request.urlopen(req) data = res.read() cal = icalendar.Calendar.from_ical(data) events = [] for event in cal.walk('vevent'): start = event.get('dtstart') if not start: continue start = start.dt if (type(start) == date): start = tz.localize(datetime.combine(start, datetime.min.time())) end = event.get('dtend') if not end: continue end = end.dt if (type(end) == date): end = tz.localize(datetime.combine(end, datetime.max.time())) repeat = event.get('rrule') if repeat: rrule = rrulestr(repeat.to_ical().decode(), ignoretz=True, dtstart=start.replace(tzinfo=None)) ruleset = rruleset() ruleset.rrule(rrule) nextRepeat = ruleset.between(recurFrom, recurTo) if (len(nextRepeat) == 0): continue start = tz.localize(nextRepeat[0]) end = tz.localize( datetime(nextRepeat[0].year, nextRepeat[0].month, nextRepeat[0].day, end.hour, end.minute, end.second)) if (end < now): continue events.append({ 'start': start, 'end': end, 'summary': event.get('summary'), 'location': event.get('location'), }) events.sort(key=lambda x: x['start']) currentEvents = [] nextEvent = None for event in events: if (event['start'] < now and event['end'] > now): currentEvents.append(clean_event(event)) if (event['start'] > now): nextEvent = event break return { 'current': currentEvents, 'next': clean_event(nextEvent), }
def get_working_days(a, b): rs = rrule.rruleset() rs.rrule(rrule.rrule(rrule.DAILY, dtstart=a, until=b)) # Get all days between a and b rs.exrule( rrule.rrule(rrule.WEEKLY, dtstart=a, byweekday=(rrule.SA, rrule.SU))) # Exclude weekends rs.exrule(get_holidays(a, b)) # Exclude holidays return rs
def init_rruleset(): rr = rruleset() rr.rrule( rrule(DAILY, byweekday=(MO, TU, WE, TH, FR), dtstart=datetime.datetime(2010, 1, 1))) for h in holidays: rr.exdate(h) return rr
def get_opex_friday(start, end): rules = [] opex_day = rrule.rrule(rrule.MONTHLY, byweekday=(rrule.FR(+3)), cache=True, dtstart=start, until=end) rules.append(opex_day) ruleset = rrule.rruleset() for rule in rules: ruleset.rrule(rule) days = ruleset.between(start, end, inc=True) return days
def _get_rruleset(self, dtstart=None, until=None): self.ensure_one() rset = rruleset() for rule in self.fsm_frequency_ids: if not rule.is_exclusive: rset.rrule(rule._get_rrule(dtstart, until)) else: rset.exrule(rule._get_rrule(dtstart)) return rset
def parse_rrule(component, tz=UTC): """ Extract a dateutil.rrule object from an icalendar component. Also includes the component's dtstart and exdate properties. The rdate and exrule properties are not yet supported. :param component: icalendar component :param tz: timezone for DST handling :return: extracted rrule or rruleset """ if component.get('rrule'): # component['rrule'] can be both a scalar and a list rrules = component['rrule'] if not isinstance(rrules, list): rrules = [rrules] # If dtstart is a datetime, make sure it's in a timezone. rdtstart = component['dtstart'].dt if type(rdtstart) is datetime: rdtstart = normalize(rdtstart, tz=tz) # Parse the rrules, might return a rruleset instance, instead of rrule rule = rrulestr('\n'.join(x.to_ical().decode() for x in rrules), dtstart=rdtstart) if component.get('exdate'): # Make sure, to work with a rruleset if isinstance(rule, rrule): rules = rruleset() rules.rrule(rule) rule = rules # Add exdates to the rruleset for exd in extract_exdates(component): rule.exdate(exd) # TODO: What about rdates and exrules? # You really want an rrule for a component without rrule? Here you are. else: rule = rruleset() rule.rdate(normalize(component['dtstart'].dt, tz=tz)) return rule
def add_meeting_to_vcal(ical, meeting, reminder=None): """ Convert a Meeting object into iCal object and add it to the provided calendar. :arg ical: the iCal calendar object to which the meetings should be added. :arg meeting: a single fedocal.model.Meeting object to convert to iCal and add to the provided calendar. :kwarg reminder: None or a datetime.timedelta instance. """ entry = ical.add('vevent') entry.add('summary').value = meeting.meeting_name if meeting.meeting_information: entry.add('description').value = meeting.meeting_information entry.add('organizer').value = ', '.join(meeting.meeting_manager) if meeting.meeting_location: entry.add('location').value = meeting.meeting_location start = entry.add('dtstart') stop = entry.add('dtend') if meeting.full_day: start.value = meeting.meeting_date stop.value = meeting.meeting_date_end entry.add('transp').value = 'TRANSPARENT' else: tz = zoneinfo.gettz(meeting.meeting_timezone) dti_start = datetime.combine( meeting.meeting_date, meeting.meeting_time_start) start.value = dti_start.replace(tzinfo=tz) dti_end = datetime.combine( meeting.meeting_date_end, meeting.meeting_time_stop) stop.value = dti_end.replace(tzinfo=tz) if meeting.recursion_frequency and meeting.recursion_ends: newrule = rrule.rruleset() freq = 1 if meeting.recursion_frequency == 14: freq = 2 newrule.rrule( rrule.rrule( freq=rrule.WEEKLY, interval=freq, dtstart=start.value, until=meeting.recursion_ends)) entry.rruleset = newrule if reminder: valarm = entry.add('valarm') valarm.add('trigger').value = reminder valarm.add('action').value = 'DISPLAY' valarm.add('description').value = ( '[{calendar_name}] [Fedocal] Reminder meeting: {meeting_name}' ).format(calendar_name=meeting.calendar_name, meeting_name=meeting.meeting_name)
def test_compare_rrule_diff(): first = iCalendar() first_vevent = first.add('vevent') first_vevent.add('dtstart').value = datetime(2001, 1, 1, 10, 0) rset = rrule.rruleset() rset.rrule(rrule.rrule(freq=rrule.DAILY, count=3)) first_vevent.rruleset = rset second = iCalendar() second_vevent = second.add('vevent') second_vevent.add('dtstart').value = datetime(2001, 1, 1, 10, 0) second_out = iCalendar() rset = rrule.rruleset() rset.rrule(rrule.rrule(freq=rrule.DAILY, count=4)) second_vevent.rruleset = rset compare(first, second, second_out) assert len(first.contents) == 1 assert len(second_out.contents) == 1
def createDateUtilFromRule(self, dtstart): """Return an appropriate dateutil.rrule.rruleset.""" ruleset = rruleset() for rtype in 'rrule', 'exrule': for rule in getattr(self, rtype + 's', []): getattr(ruleset, rtype)(rule.createDateUtilFromRule(dtstart)) for datetype in 'rdate', 'exdate': for date in getattr(self, datetype + 's', []): getattr(ruleset, datetype)(date) return ruleset
def thanksgiving(start=date.today(), end=date.today() + timedelta(days=365)): ''' Example for one date. ''' rs = rrule.rruleset() rs.rrule( rrule.rrule(rrule.YEARLY, dtstart=start, until=end, bymonth=11, byweekday=rrule.TH(4))) return rs
def ical_feed(request): # We need an appropriate hostname if Site._meta.installed: current_site = Site.objects.get_current() else: current_site = RequestSite(request) # Calendar object with various settings needed cal = vobject.iCalendar() cal.add('X-WR-TIMEZONE').value = settings.TIME_ZONE cal.add('X-WR-CALNAME').value = 'Events' cal.add('X-WR-CALDESC').value = 'Events Calendar' cal.add('CALSCALE').value = 'GREGORIAN' cal.add('method').value = 'PUBLISH' # IE/Outlook needs this # Events for event in Event.objects.all().prefetch_related('recurringevent_set', 'recurringeventexclusion_set'): if event.recurringevent_set.all(): # Recurring event for i in event.recurringevent_set.all(): v = cal.add('vevent') v.add('uid').value = 'recurring-event-%d@%s' % (i.id, current_site) v.add('summary').value = event.title v.add('dtstart').value = event.start v.add('dtend').value = event.end event_ruleset = rrule.rruleset() event_ruleset.rrule(i.rrule()) # Add in any exclusions for j in event.recurringeventexclusion_set.all(): event_ruleset.exdate(j.date) v.rruleset = event_ruleset else: # One off event v = cal.add('vevent') v.add('uid').value = 'event-%d@%s' % (event.id, current_site) v.add('summary').value = event.title v.add('dtstart').value = event.start v.add('dtend').value = event.end icalstream = cal.serialize() response = HttpResponse(icalstream, mimetype='text/calendar') response['Filename'] = 'events.ics' # IE needs this response['Content-Disposition'] = 'attachment; filename=events.ics' return response
def get_start_times(event, start=None, end=None): # Expands the rrule on event to return a list of arrow datetimes # representing start times for its recurring instances. # If start and/or end are supplied, will return times within that range, # otherwise defaults to the event start date and now + 1 year; # this can return a lot of instances if the event recurs more frequently # than weekly! if isinstance(event, RecurringEvent): # Localize first so that expansion covers DST if event.start_timezone: event.start = event.start.to(event.start_timezone) if not start: start = event.start else: start = arrow.get(start) if not end: end = arrow.utcnow().replace(years=+EXPAND_RECURRING_YEARS) else: end = arrow.get(end) rrules = parse_rrule(event) if not rrules: log.warn('Tried to expand a non-recurring event', event_id=event.id) return [event.start] excl_dates = parse_exdate(event) if len(excl_dates) > 0: if not isinstance(rrules, rruleset): rrules = rruleset().rrule(rrules) # We want naive-everything for all-day events. if event.all_day: excl_dates = map(lambda x: x.naive, excl_dates) map(rrules.exdate, excl_dates) # Return all start times between start and end, including start and # end themselves if they obey the rule. if event.all_day: # compare naive times, since date handling in rrulestr is naive # when UNTIL takes the form YYYYMMDD start = start.to('utc').naive end = end.to('utc').naive start_times = rrules.between(start, end, inc=True) # Convert back to UTC, which covers daylight savings differences start_times = [arrow.get(t).to('utc') for t in start_times] return start_times return [event.start]
def __init__(self): BaseCalendarTest.__init__(self) self.cal = Calendar(workdays=[0,1,4,6]) rr = rruleset() rr.rrule(rrule(DAILY, byweekday=(MO,TU,FR,SU), dtstart=datetime.datetime(2010,1,1))) self.rr = rr self.dates = rr.between(datetime.datetime(2010,1,1), datetime.datetime(2013,12,31), inc=True)
def workday_count(alpha, omega): """ Расчёт рабочих дней с учетов выходных. """ dates = rrule.rruleset() # create an rrule.rruleset instance dates.rrule(rrule.rrule(DAILY, dtstart=alpha, until=omega)) # this set is INCLUSIVE of alpha and omega dates.exrule(rrule.rrule(DAILY, byweekday=(rrule.SA, rrule.SU), dtstart=alpha)) # here's where we exclude the weekend dates return len(list(dates)) # there's probably a faster way to handle this
def set_recurrence_from_string(self, rrule_data): """ rrule_data is a string representing one or several rule in iCalendar format """ rrule_temp = rrulestr(rrule_data, forceset=True, dtstart=self.start_datetime) if isinstance(rrule_temp, rruleset): self._recurrence = rrule_temp else: # rrule self._recurrence = rruleset() self._recurrence.rrule(rrule_temp) return self._recurrence
def days(start, stop): """ Return days between start & stop (inclusive) Note that start must be less than stop or else 0 is returned. @param start: Start date @param stop: Stop date @return int """ dates=rrule.rruleset() # Get dates between start/stop (which are inclusive) dates.rrule(rrule.rrule(rrule.DAILY, dtstart=start, until=stop)) return dates.count()
def __init__(self): BaseCalendarTest.__init__(self) self.holidays = [parse(x) for x in global_holidays.split('\n')] self.cal = Calendar(workdays=[0], holidays=self.holidays) rr = rruleset() rr.rrule(rrule(DAILY, byweekday=(MO), dtstart=datetime.datetime(2010,1,1))) for h in self.holidays: rr.exdate(h) self.rr = rr self.dates = rr.between(datetime.datetime(2010,1,1), datetime.datetime(2013,12,31), inc=True)
def passed_weekdays(): today = date.today() # Use dateutils ruleset to count the number of working days (we are # definging that as mon-fri) between two dates. dates = rrule.rruleset() dates.rrule(rrule.rrule(rrule.DAILY, dtstart=THE_BEGINNING_OF_TIME, until=today)) dates.exrule(rrule.rrule(rrule.DAILY, byweekday=(rrule.SA, rrule.SU), dtstart=THE_BEGINNING_OF_TIME)) #This is includive of start and end dates - so to normalise and make it # the same as the daily calcs, remove one. passed_weekdays = dates.count() - 1 return passed_weekdays
def rruleset(self): if self.start is None: return None rrs = rruleset(cache=True) if self.frequency is not None: rrs.rrule(self.build_rrule()) elif not self.rdates: # no rules or rdates, nothing to do return None for dt in self.rdates: rrs.rdate(dt) for dt in self.exdates: rrs.exdate(dt) return rrs
def set_recurrence(self, rrule_data): """ rrule_data can be either a rrule, a rruleset or a string reprensenting one or several rrule in iCalendar format """ if isinstance(rrule_data, rruleset): self._recurrence = rrule_data elif isinstance(rrule_data, rrule): self._recurrence = rruleset() self._recurrence.rrule(rrule_data) elif isinstance(rrule_data, basestring): self.set_recurrence_from_string(rrule_data) else: raise TypeError, "don't know how to handle provided "\ "recurrence infos" return self._recurrence