def coerceIfDatetime(value): if isinstance(value, datetime): if convertFloating and tzinfo == view.tzinfo.floating: value = coerceTimeZone(view, value, tzinfo).replace(tzinfo=None) else: value = coerceTimeZone(view, value, tzinfo) return value
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 setRuleFromDateUtil(self, rrule): """Extract attributes from rrule, set them in self. @param rrule: The rule to marshall into Chandler @type rrule: C{dateutil.rrule.rrule} """ view = self.itsView self.untilIsDate = False until = None # assume no limit if rrule._count is not None: self.isCount = True until = rrule[-1] self.wkst = fromDateUtilWeekday(rrule._wkst) self.freq = fromDateUtilFrequency(rrule._freq) # ignore byweekday if freq is WEEKLY and day correlates with dtstart # because it was automatically set by dateutil if rrule._freq != dateutil.rrule.WEEKLY or \ len(rrule._byweekday or ()) != 1 or \ rrule._dtstart.weekday() != rrule._byweekday[0]: listOfDayTuples = [] if rrule._byweekday: # Day tuples are (dayOrdinal, n-th week of the month), # 0 means all weeks listOfDayTuples = [(day, 0) for day in rrule._byweekday] if rrule._bynweekday is not None: listOfDayTuples.extend(rrule._bynweekday) if len(listOfDayTuples) > 0: self.byweekday = [] for day, n in listOfDayTuples: day = fromDateUtilWeekday(day) self.byweekday.append(WeekdayAndPositionStruct(day, n)) if rrule._until is not None: until = rrule._until if rrule._interval != 1: self.interval = rrule._interval if until is None: if self.hasLocalAttributeValue('until'): del self.until else: if until.tzinfo is None: self.until = until.replace(tzinfo=view.tzinfo.floating) else: self.until = coerceTimeZone(view, until, view.tzinfo.default) for key in self.listNames: # TODO: cache getattr(rrule, '_' + key) value = getattr(rrule, '_' + key) if key == 'bymonthday': if value is not None: value += (rrule._bynmonthday or ()) if value is not None and \ (key not in self.interpretedNames or \ len(value) > 1): # cast tuples to list setattr(self, key, list(value)) # bymonthday and bymonth may be set automatically by dateutil, if so, # unset them if rrule._freq in (dateutil.rrule.MONTHLY, dateutil.rrule.YEARLY): if len(rrule._bymonthday) == 1 and len(rrule._bynmonthday) == 0: if rrule._bymonthday[0] == rrule._dtstart.day: del self.bymonthday if rrule._freq == dateutil.rrule.YEARLY: if len(rrule._bymonth or ()) == 1 and \ rrule._byweekday is None and \ len(rrule._bynweekday or ()) == 0: if rrule._bymonth[0] == rrule._dtstart.month: del self.bymonth
def setRuleFromDateUtil(self, rrule): """Extract attributes from rrule, set them in self. @param rrule: The rule to marshall into Chandler @type rrule: C{dateutil.rrule.rrule} """ view = self.itsView self.untilIsDate = False until = None # assume no limit if rrule._count is not None: self.isCount = True until = rrule[-1] self.wkst = fromDateUtilWeekday(rrule._wkst) self.freq = fromDateUtilFrequency(rrule._freq) # ignore byweekday if freq is WEEKLY and day correlates with dtstart # because it was automatically set by dateutil if rrule._freq != dateutil.rrule.WEEKLY or \ len(rrule._byweekday or ()) != 1 or \ rrule._dtstart.weekday() != rrule._byweekday[0]: listOfDayTuples = [] if rrule._byweekday: # Day tuples are (dayOrdinal, n-th week of the month), # 0 means all weeks listOfDayTuples=[(day, 0) for day in rrule._byweekday] if rrule._bynweekday is not None: listOfDayTuples.extend(rrule._bynweekday) if len(listOfDayTuples) > 0: self.byweekday = [] for day, n in listOfDayTuples: day = fromDateUtilWeekday(day) self.byweekday.append(WeekdayAndPositionStruct(day, n)) if rrule._until is not None: until = rrule._until if rrule._interval != 1: self.interval = rrule._interval if until is None: if self.hasLocalAttributeValue('until'): del self.until else: if until.tzinfo is None: self.until = until.replace(tzinfo=view.tzinfo.floating) else: self.until = coerceTimeZone(view, until, view.tzinfo.default) for key in self.listNames: # TODO: cache getattr(rrule, '_' + key) value = getattr(rrule, '_' + key) if key == 'bymonthday': if value is not None: value += (rrule._bynmonthday or ()) if value is not None and \ (key not in self.interpretedNames or \ len(value) > 1): # cast tuples to list setattr(self, key, list(value)) # bymonthday and bymonth may be set automatically by dateutil, if so, # unset them if rrule._freq in (dateutil.rrule.MONTHLY, dateutil.rrule.YEARLY): if len(rrule._bymonthday) == 1 and len(rrule._bynmonthday) == 0: if rrule._bymonthday[0] == rrule._dtstart.day: del self.bymonthday if rrule._freq == dateutil.rrule.YEARLY: if len(rrule._bymonth or ()) == 1 and \ rrule._byweekday is None and \ len(rrule._bynweekday or ()) == 0: if rrule._bymonth[0] == rrule._dtstart.month: del self.bymonth