コード例 #1
0
    def testParse(self):

        for item in TestRecurrence.items:
            recur = Recurrence()
            recur.parse(item)
            self.assertEqual(recur.getText(), item,
                             "Failed to parse and re-generate '%s'" % (item, ))
コード例 #2
0
    def testMonthlyInUTC(self):

        recur = Recurrence()
        recur.parse("FREQ=MONTHLY")
        start = DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(utc=True))
        end = DateTime(2015, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
        items = []
        range = Period(start, end)
        recur.expand(DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")), range, items)
        self.assertEqual(
            items,
            [
                DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 2, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 3, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 4, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 5, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 6, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 7, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 8, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 9, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 10, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 11, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 12, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
            ],
        )
コード例 #3
0
    def testHash(self):

        hashes = []
        for item in TestRecurrence.items:
            recur = Recurrence()
            recur.parse(item)
            hashes.append(hash(recur))
        hashes.sort()
        for i in range(1, len(hashes)):
            self.assertNotEqual(hashes[i - 1], hashes[i])
コード例 #4
0
    def testHash(self):

        hashes = []
        for item in TestRecurrence.items:
            recur = Recurrence()
            recur.parse(item)
            hashes.append(hash(recur))
        hashes.sort()
        for i in range(1, len(hashes)):
            self.assertNotEqual(hashes[i - 1], hashes[i])
コード例 #5
0
    def testInequality(self):

        recur1 = Recurrence()
        recur1.parse("FREQ=YEARLY;COUNT=400")
        recur2 = Recurrence()
        recur2.parse("COUNT=400;FREQ=YEARLY;BYMONTH=1")

        self.assertNotEqual(recur1, recur2)
コード例 #6
0
ファイル: instances.py プロジェクト: eventable/PyCalendar
def instances(start, rrule):
    """
    Expand an RRULE.
    """

    recur = Recurrence()
    recur.parse(rrule)
    start = DateTime.parseText(start)
    end = start.duplicate()
    end.offsetYear(100)
    items = []
    range = Period(start, end)
    recur.expand(start, range, items)
    print("DTSTART:{}".format(start))
    print("RRULE:{}".format(rrule))
    print("Instances: {}".format(", ".join(map(str, items))))
コード例 #7
0
    def testMonthlyInUTC(self):

        recur = Recurrence()
        recur.parse("FREQ=MONTHLY")
        start = DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(utc=True))
        end = DateTime(2015, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
        items = []
        range = Period(start, end)
        recur.expand(DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")), range, items)
        self.assertEqual(
            items,
            [
                DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 2, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 3, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 4, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 5, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 6, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 7, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 8, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 9, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 10, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 11, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 12, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
            ],
        )
コード例 #8
0
    def testExampleRules(self):

        examples = os.path.join(os.path.dirname(__file__), "rrule_examples.json")
        with open(examples) as f:
            examples = json.loads(f.read())

        for ctr, i in enumerate(examples):

            recur = Recurrence()
            recur.parse(i["rule"])
            start = DateTime.parseText(i["start"])
            end = DateTime.parseText(i["end"])
            results = map(DateTime.parseText, i["results"])

            items = []
            range = Period(start, end)
            recur.expand(start, range, items)
            self.assertEqual(
                items,
                results,
                msg="Failed rule: #{} {}".format(ctr + 1, i["rule"])
            )
コード例 #9
0
    def testInequality(self):

        recur1 = Recurrence()
        recur1.parse("FREQ=YEARLY;COUNT=400")
        recur2 = Recurrence()
        recur2.parse("COUNT=400;FREQ=YEARLY;BYMONTH=1")

        self.assertNotEqual(recur1, recur2)
コード例 #10
0
    def testWeeklyTwice(self):

        recur = Recurrence()
        recur.parse("FREQ=WEEKLY")
        start = DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(utc=True))
        end = DateTime(2014, 2, 1, 0, 0, 0, tzid=Timezone(utc=True))
        items = []
        range = Period(start, end)
        recur.expand(DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")), range, items)
        self.assertEqual(
            items,
            [
                DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 8, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 15, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 22, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 29, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),

            ],
        )

        start = DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(utc=True))
        end = DateTime(2014, 3, 1, 0, 0, 0, tzid=Timezone(utc=True))
        items = []
        range = Period(start, end)
        recur.expand(DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")), range, items)
        self.assertEqual(
            items,
            [
                DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 8, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 15, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 22, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 29, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 2, 5, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 2, 12, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 2, 19, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 2, 26, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
            ],
        )
コード例 #11
0
    def testParseInvalid(self):

        items = (
            "",
            "FREQ=",
            "FREQ=MICROSECONDLY",
            "FREQ=YEARLY;COUNT=ABC",
            "FREQ=YEARLY;COUNT=123;UNTIL=20110102",
            "FREQ=MONTHLY;UNTIL=20110102T",
            "FREQ=MONTHLY;UNTIL=20110102t090000",
            "FREQ=MONTHLY;UNTIL=20110102T100000z",
            "FREQ=MONTHLY;UNTIL=20110102TAABBCCz",
            "FREQ=MONTHLY;BYDAY=A",
            "FREQ=MONTHLY;BYDAY=+1,3MO",
            "FREQ=MONTHLY;BYHOUR=A",
            "FREQ=MONTHLY;BYHOUR=54",
        )

        for item in items:
            self.assertRaises(ValueError, Recurrence().parse, item)
コード例 #12
0
def instances(start, rrule):
    """
    Expand an RRULE.
    """

    recur = Recurrence()
    recur.parse(rrule)
    start = DateTime.parseText(start)
    end = start.duplicate()
    end.offsetYear(100)
    items = []
    range = Period(start, end)
    recur.expand(start, range, items)
    print("DTSTART:{}".format(start))
    print("RRULE:{}".format(rrule))
    print("Instances: {}".format(", ".join(map(str, items))))
コード例 #13
0
    def testWeeklyTwice(self):

        recur = Recurrence()
        recur.parse("FREQ=WEEKLY")
        start = DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(utc=True))
        end = DateTime(2014, 2, 1, 0, 0, 0, tzid=Timezone(utc=True))
        items = []
        range = Period(start, end)
        recur.expand(DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")), range, items)
        self.assertEqual(
            items,
            [
                DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 8, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 15, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 22, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 29, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),

            ],
        )

        start = DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(utc=True))
        end = DateTime(2014, 3, 1, 0, 0, 0, tzid=Timezone(utc=True))
        items = []
        range = Period(start, end)
        recur.expand(DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")), range, items)
        self.assertEqual(
            items,
            [
                DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 8, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 15, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 22, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 1, 29, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 2, 5, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 2, 12, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 2, 19, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
                DateTime(2014, 2, 26, 12, 0, 0, tzid=Timezone(tzid="America/New_York")),
            ],
        )
コード例 #14
0
    def testExampleRules(self):

        examples = os.path.join(os.path.dirname(__file__),
                                "rrule_examples.json")
        with open(examples) as f:
            examples = json.loads(f.read())

        for ctr, i in enumerate(examples):

            recur = Recurrence()
            recur.parse(i["rule"])
            start = DateTime.parseText(i["start"])
            end = DateTime.parseText(i["end"])
            results = map(DateTime.parseText, i["results"])

            items = []
            range = Period(start, end)
            recur.expand(start, range, items)
            self.assertEqual(items,
                             results,
                             msg="Failed rule: #{} {}".format(
                                 ctr + 1, i["rule"]))
コード例 #15
0
    def testClearOnChange(self):

        recur = Recurrence()
        recur.parse("FREQ=DAILY")

        start = DateTime(2013, 1, 1, 0, 0, 0)
        end = DateTime(2017, 1, 1, 0, 0, 0)
        range = Period(start, end)
        items = []
        recur.expand(start, range, items)
        self.assertTrue(recur.mCached)
        self.assertTrue(len(items) > 100)

        recur.setUseCount(True)
        recur.setCount(10)
        self.assertFalse(recur.mCached)
        items = []
        recur.expand(start, range, items)
        self.assertEqual(len(items), 10)
コード例 #16
0
    def testClearOnChange(self):

        recur = Recurrence()
        recur.parse("FREQ=DAILY")

        start = DateTime(2013, 1, 1, 0, 0, 0)
        end = DateTime(2017, 1, 1, 0, 0, 0)
        range = Period(start, end)
        items = []
        recur.expand(start, range, items)
        self.assertTrue(recur.mCached)
        self.assertTrue(len(items) > 100)

        recur.setUseCount(True)
        recur.setCount(10)
        self.assertFalse(recur.mCached)
        items = []
        recur.expand(start, range, items)
        self.assertEqual(len(items), 10)
コード例 #17
0
    def vtimezone(self, vtz, zonerule, start, end, offsetfrom, offsetto, instanceCount):
        """
        Generate a VTIMEZONE sub-component for this Rule.

        @param vtz: VTIMEZONE to add to
        @type vtz: L{VTimezone}
        @param zonerule: the Zone rule line being used
        @type zonerule: L{ZoneRule}
        @param start: the start time for the first instance
        @type start: L{DateTime}
        @param end: the start time for the last instance
        @type end: L{DateTime}
        @param offsetfrom: the UTC offset-from
        @type offsetfrom: C{int}
        @param offsetto: the UTC offset-to
        @type offsetto: C{int}
        @param instanceCount: the number of instances in the set
        @type instanceCount: C{int}
        """

        # Determine type of component based on offset
        dstoffset = self.getOffset()
        if dstoffset == 0:
            comp = Standard(parent=vtz)
        else:
            comp = Daylight(parent=vtz)

        # Do offsets
        tzoffsetfrom = UTCOffsetValue(offsetfrom)
        tzoffsetto = UTCOffsetValue(offsetto)

        comp.addProperty(Property(definitions.cICalProperty_TZOFFSETFROM, tzoffsetfrom))
        comp.addProperty(Property(definitions.cICalProperty_TZOFFSETTO, tzoffsetto))

        # Do TZNAME
        if zonerule.format.find("%") != -1:
            tzname = zonerule.format % (self.letter if self.letter != "-" else "",)
        else:
            tzname = zonerule.format
        comp.addProperty(Property(definitions.cICalProperty_TZNAME, tzname))

        # Do DTSTART
        comp.addProperty(Property(definitions.cICalProperty_DTSTART, start))

        # Now determine the recurrences (use RDATE if only one year or
        # number of instances is one)
        if self.toYear != "only" and instanceCount != 1:
            rrule = Recurrence()
            rrule.setFreq(definitions.eRecurrence_YEARLY)
            rrule.setByMonth((Rule.MONTH_NAME_TO_POS[self.inMonth],))
            if self.onDay in Rule.LASTDAY_NAME_TO_RDAY:

                # Need to check whether day has changed due to time shifting
                dayOfWeek = start.getDayOfWeek()
                indicatedDay = Rule.LASTDAY_NAME_TO_DAY[self.onDay]

                if dayOfWeek == indicatedDay:
                    rrule.setByDay(((-1, Rule.LASTDAY_NAME_TO_RDAY[self.onDay]),))
                elif dayOfWeek < indicatedDay or dayOfWeek == 6 and indicatedDay == 0:
                    # This is OK as we have moved back a day and thus no month transition
                    # could have occurred
                    fakeOffset = daysInMonth(start.getMonth(), start.getYear()) - 6
                    offset, rday, bymday = self.getOnDayDetails(start, indicatedDay, fakeOffset)
                    if bymday:
                        rrule.setByMonthDay(bymday)
                    rrule.setByDay(((offset, rday),))
                else:
                    # This is bad news as we have moved forward a day possibly into the next month
                    # What we do is switch to using a BYYEARDAY rule with offset from the end of the year
                    rrule.setByMonth(())
                    daysBackStartOfMonth = (
                        365, 334, 306, 275, 245, 214, 184, 153, 122, 92, 61, 31, 0     # Does not account for leap year
                    )
                    rrule.setByYearDay([-(daysBackStartOfMonth[Rule.MONTH_NAME_TO_POS[self.inMonth]] + i) for i in range(7)])
                    rrule.setByDay(
                        ((0, divmod(Rule.LASTDAY_NAME_TO_DAY[self.onDay] + 1, 7)[1]),),
                    )

            elif self.onDay.find(">=") != -1:
                indicatedDay, dayoffset = self.onDay.split(">=")

                # Need to check whether day has changed due to time shifting
                dayOfWeek = start.getDayOfWeek()
                indicatedDay = Rule.DAY_NAME_TO_DAY[indicatedDay]

                if dayOfWeek == indicatedDay:
                    offset, rday, bymday = self.getOnDayDetails(start, indicatedDay, int(dayoffset))
                    if bymday:
                        rrule.setByMonthDay(bymday)
                    rrule.setByDay(((offset, rday),))
                elif dayoffset == 1 and divmod(dayoffset - indicatedDay, 7)[1] == 6:
                    # This is bad news as we have moved backward a day possibly into the next month
                    # What we do is switch to using a BYYEARDAY rule with offset from the end of the year
                    rrule.setByMonth(())
                    daysBackStartOfMonth = (
                        365, 334, 306, 275, 245, 214, 184, 153, 122, 92, 61, 31, 0     # Does not account for leap year
                    )
                    rrule.setByYearDay([-(daysBackStartOfMonth[Rule.MONTH_NAME_TO_POS[self.inMonth]] + i) for i in range(7)])
                    rrule.setByDay(
                        ((0, divmod(indicatedDay + 1, 7)[1]),),
                    )
                else:
                    # This is OK as we have moved forward a day and thus no month transition
                    # could have occurred
                    offset, rday, bymday = self.getOnDayDetails(start, indicatedDay, int(dayoffset))
                    if bymday:
                        rrule.setByMonthDay(bymday)
                    rrule.setByDay(((offset, rday),))
            else:
                try:
                    int(self.onDay)
                except:
                    assert False, "onDay value is not recognized: %s" % (self.onDay,)

            # Add any UNTIL
            if zonerule.getUntilDate().dt.getYear() < 9999 or self.endYear() < 9999:
                until = end.duplicate()
                until.offsetSeconds(-offsetfrom)
                until.setTimezoneUTC(True)
                rrule.setUseUntil(True)
                rrule.setUntil(until)

            comp.addProperty(Property(definitions.cICalProperty_RRULE, rrule))
        else:
            comp.addProperty(Property(definitions.cICalProperty_RDATE, start))

        comp.finalise()
        vtz.addComponent(comp)
コード例 #18
0
    def testParse(self):

        for item in TestRecurrence.items:
            recur = Recurrence()
            recur.parse(item)
            self.assertEqual(recur.getText(), item, "Failed to parse and re-generate '%s'" % (item,))
コード例 #19
0
ファイル: rule.py プロジェクト: eventable/PyCalendar
    def vtimezone(self, vtz, zonerule, start, end, offsetfrom, offsetto, instanceCount):
        """
        Generate a VTIMEZONE sub-component for this Rule.

        @param vtz: VTIMEZONE to add to
        @type vtz: L{VTimezone}
        @param zonerule: the Zone rule line being used
        @type zonerule: L{ZoneRule}
        @param start: the start time for the first instance
        @type start: L{DateTime}
        @param end: the start time for the last instance
        @type end: L{DateTime}
        @param offsetfrom: the UTC offset-from
        @type offsetfrom: C{int}
        @param offsetto: the UTC offset-to
        @type offsetto: C{int}
        @param instanceCount: the number of instances in the set
        @type instanceCount: C{int}
        """

        # Determine type of component based on offset
        dstoffset = self.getOffset()
        if dstoffset == 0:
            comp = Standard(parent=vtz)
        else:
            comp = Daylight(parent=vtz)

        # Do offsets
        tzoffsetfrom = UTCOffsetValue(offsetfrom)
        tzoffsetto = UTCOffsetValue(offsetto)

        comp.addProperty(Property(definitions.cICalProperty_TZOFFSETFROM, tzoffsetfrom))
        comp.addProperty(Property(definitions.cICalProperty_TZOFFSETTO, tzoffsetto))

        # Do TZNAME
        if zonerule.format.find("%") != -1:
            tzname = zonerule.format % (self.letter if self.letter != "-" else "",)
        else:
            tzname = zonerule.format
        comp.addProperty(Property(definitions.cICalProperty_TZNAME, tzname))

        # Do DTSTART
        comp.addProperty(Property(definitions.cICalProperty_DTSTART, start))

        # Now determine the recurrences (use RDATE if only one year or
        # number of instances is one)
        if self.toYear != "only" and instanceCount != 1:
            rrule = Recurrence()
            rrule.setFreq(definitions.eRecurrence_YEARLY)
            rrule.setByMonth((Rule.MONTH_NAME_TO_POS[self.inMonth],))
            if self.onDay in Rule.LASTDAY_NAME_TO_RDAY:

                # Need to check whether day has changed due to time shifting
                dayOfWeek = start.getDayOfWeek()
                indicatedDay = Rule.LASTDAY_NAME_TO_DAY[self.onDay]

                if dayOfWeek == indicatedDay:
                    rrule.setByDay(((-1, Rule.LASTDAY_NAME_TO_RDAY[self.onDay]),))
                elif dayOfWeek < indicatedDay or dayOfWeek == 6 and indicatedDay == 0:
                    # This is OK as we have moved back a day and thus no month transition
                    # could have occurred
                    fakeOffset = daysInMonth(start.getMonth(), start.getYear()) - 6
                    offset, rday, bymday = self.getOnDayDetails(start, indicatedDay, fakeOffset)
                    if bymday:
                        rrule.setByMonthDay(bymday)
                    rrule.setByDay(((offset, rday),))
                else:
                    # This is bad news as we have moved forward a day possibly into the next month
                    # What we do is switch to using a BYYEARDAY rule with offset from the end of the year
                    rrule.setByMonth(())
                    daysBackStartOfMonth = (
                        365, 334, 306, 275, 245, 214, 184, 153, 122, 92, 61, 31, 0     # Does not account for leap year
                    )
                    rrule.setByYearDay([-(daysBackStartOfMonth[Rule.MONTH_NAME_TO_POS[self.inMonth]] + i) for i in range(7)])
                    rrule.setByDay(
                        ((0, divmod(Rule.LASTDAY_NAME_TO_DAY[self.onDay] + 1, 7)[1]),),
                    )

            elif self.onDay.find(">=") != -1:
                indicatedDay, dayoffset = self.onDay.split(">=")

                # Need to check whether day has changed due to time shifting
                dayOfWeek = start.getDayOfWeek()
                indicatedDay = Rule.DAY_NAME_TO_DAY[indicatedDay]

                if dayOfWeek == indicatedDay:
                    offset, rday, bymday = self.getOnDayDetails(start, indicatedDay, int(dayoffset))
                    if bymday:
                        rrule.setByMonthDay(bymday)
                    rrule.setByDay(((offset, rday),))
                elif dayoffset == 1 and divmod(dayoffset - indicatedDay, 7)[1] == 6:
                    # This is bad news as we have moved backward a day possibly into the next month
                    # What we do is switch to using a BYYEARDAY rule with offset from the end of the year
                    rrule.setByMonth(())
                    daysBackStartOfMonth = (
                        365, 334, 306, 275, 245, 214, 184, 153, 122, 92, 61, 31, 0     # Does not account for leap year
                    )
                    rrule.setByYearDay([-(daysBackStartOfMonth[Rule.MONTH_NAME_TO_POS[self.inMonth]] + i) for i in range(7)])
                    rrule.setByDay(
                        ((0, divmod(indicatedDay + 1, 7)[1]),),
                    )
                else:
                    # This is OK as we have moved forward a day and thus no month transition
                    # could have occurred
                    offset, rday, bymday = self.getOnDayDetails(start, indicatedDay, int(dayoffset))
                    if bymday:
                        rrule.setByMonthDay(bymday)
                    rrule.setByDay(((offset, rday),))
            else:
                try:
                    _ignore_day = int(self.onDay)
                except:
                    assert False, "onDay value is not recognized: %s" % (self.onDay,)

            # Add any UNTIL
            if zonerule.getUntilDate().dt.getYear() < 9999 or self.endYear() < 9999:
                until = end.duplicate()
                until.offsetSeconds(-offsetfrom)
                until.setTimezoneUTC(True)
                rrule.setUseUntil(True)
                rrule.setUntil(until)

            comp.addProperty(Property(definitions.cICalProperty_RRULE, rrule))
        else:
            comp.addProperty(Property(definitions.cICalProperty_RDATE, start))

        comp.finalise()
        vtz.addComponent(comp)