(self, tzinfo, start=2000, end=2030)
Create appropriate objects in self to represent tzinfo.

        Collapse DST transitions to rrules as much as possible.

        Assumptions:
        - DST <-> Standard transitions occur on the hour
        - never within a month of one another
        - twice or fewer times a year
        - never in the month of December
        - DST always moves offset exactly one hour later
        - tzinfo classes dst method always treats times that could be in either
          offset as being in the later regime
Create appropriate objects in self to represent tzinfo.
Create appropriate objects in self to represent tzinfo .
def settzinfo(self, tzinfo, start=2000, end=2030):
        """
        Create appropriate objects in self to represent tzinfo.

        Collapse DST transitions to rrules as much as possible.

        Assumptions:
        - DST <-> Standard transitions occur on the hour
        - never within a month of one another
        - twice or fewer times a year
        - never in the month of December
        - DST always moves offset exactly one hour later
        - tzinfo classes dst method always treats times that could be in either
          offset as being in the later regime
        """
        def fromLastWeek(dt):
            """
            How many weeks from the end of the month dt is, starting from 1.
            """
            weekDelta = datetime.timedelta(weeks=1)
            n = 1
            current = dt + weekDelta
            while current.month == dt.month:
                n += 1
                current += weekDelta
            return n

        # lists of dictionaries defining rules which are no longer in effect
        completed = {'daylight': [], 'standard': []}

        # dictionary defining rules which are currently in effect
        working = {'daylight': None, 'standard': None}

        # rule may be based on nth week of the month or the nth from the last
        for year in range(start, end + 1):
            newyear = datetime.datetime(year, 1, 1)
            for transitionTo in 'daylight', 'standard':
                transition = getTransition(transitionTo, year, tzinfo)
                oldrule = working[transitionTo]

                if transition == newyear:
                    # transitionTo is in effect for the whole year
                    rule = {'end'        : None,
                            'start'      : newyear,
                            'month'      : 1,
                            'weekday'    : None,
                            'hour'       : None,
                            'plus'       : None,
                            'minus'      : None,
                            'name'       : tzinfo.tzname(newyear),
                            'offset'     : tzinfo.utcoffset(newyear),
                            'offsetfrom' : tzinfo.utcoffset(newyear)}
                    if oldrule is None:
                        # transitionTo was not yet in effect
                        working[transitionTo] = rule
                    else:
                        # transitionTo was already in effect
                        if (oldrule['offset'] != tzinfo.utcoffset(newyear)):
                            # old rule was different, it shouldn't continue
                            oldrule['end'] = year - 1
                            completed[transitionTo].append(oldrule)
                            working[transitionTo] = rule
                elif transition is None:
                    # transitionTo is not in effect
                    if oldrule is not None:
                        # transitionTo used to be in effect
                        oldrule['end'] = year - 1
                        completed[transitionTo].append(oldrule)
                        working[transitionTo] = None
                else:
                    # an offset transition was found
                    try:
                        old_offset = tzinfo.utcoffset(transition - twoHours)
                        name = tzinfo.tzname(transition)
                        offset = tzinfo.utcoffset(transition)
                    except (pytz.AmbiguousTimeError, pytz.NonExistentTimeError):
                        # guaranteed that tzinfo is a pytz timezone
                        is_dst = (transitionTo == "daylight")
                        old_offset = tzinfo.utcoffset(transition - twoHours, is_dst=is_dst)
                        name = tzinfo.tzname(transition, is_dst=is_dst)
                        offset = tzinfo.utcoffset(transition, is_dst=is_dst)
                    rule = {'end'     : None,  # None, or an integer year
                            'start'   : transition,  # the datetime of transition
                            'month'   : transition.month,
                            'weekday' : transition.weekday(),
                            'hour'    : transition.hour,
                            'name'    : name,
                            'plus'    : int(
                                (transition.day - 1)/ 7 + 1),  # nth week of the month
                            'minus'   : fromLastWeek(transition),  # nth from last week
                            'offset'  : offset,
                            'offsetfrom' : old_offset}

                    if oldrule is None:
                        working[transitionTo] = rule
                    else:
                        plusMatch = rule['plus'] == oldrule['plus']
                        minusMatch = rule['minus'] == oldrule['minus']
                        truth = plusMatch or minusMatch
                        for key in 'month', 'weekday', 'hour', 'offset':
                            truth = truth and rule[key] == oldrule[key]
                        if truth:
                            # the old rule is still true, limit to plus or minus
                            if not plusMatch:
                                oldrule['plus'] = None
                            if not minusMatch:
                                oldrule['minus'] = None
                        else:
                            # the new rule did not match the old
                            oldrule['end'] = year - 1
                            completed[transitionTo].append(oldrule)
                            working[transitionTo] = rule

        for transitionTo in 'daylight', 'standard':
            if working[transitionTo] is not None:
                completed[transitionTo].append(working[transitionTo])

        self.tzid = []
        self.daylight = []
        self.standard = []

        self.add('tzid').value = self.pickTzid(tzinfo, True)

        # old = None # unused?
        for transitionTo in 'daylight', 'standard':
            for rule in completed[transitionTo]:
                comp = self.add(transitionTo)
                dtstart = comp.add('dtstart')
                dtstart.value = rule['start']
                if rule['name'] is not None:
                    comp.add('tzname').value = rule['name']
                line = comp.add('tzoffsetto')
                line.value = deltaToOffset(rule['offset'])
                line = comp.add('tzoffsetfrom')
                line.value = deltaToOffset(rule['offsetfrom'])

                if rule['plus'] is not None:
                    num = rule['plus']
                elif rule['minus'] is not None:
                    num = -1 * rule['minus']
                else:
                    num = None
                if num is not None:
                    dayString = ";BYDAY=" + str(num) + WEEKDAYS[rule['weekday']]
                else:
                    dayString = ""
                if rule['end'] is not None:
                    if rule['hour'] is None:
                        # all year offset, with no rule
                        endDate = datetime.datetime(rule['end'], 1, 1)
                    else:
                        weekday = rrule.weekday(rule['weekday'], num)
                        du_rule = rrule.rrule(rrule.YEARLY,
                            bymonth=rule['month'], byweekday=weekday,
                            dtstart=datetime.datetime(
                               rule['end'], 1, 1, rule['hour']
                            )
                        )
                        endDate = du_rule[0]
                    endDate = endDate.replace(tzinfo=utc) - rule['offsetfrom']
                    endString = ";UNTIL=" + dateTimeToString(endDate)
                else:
                    endString = ''
                new_rule = "FREQ=YEARLY{0!s};BYMONTH={1!s}{2!s}"\
                    .format(dayString, rule['month'], endString)

                comp.add('rrule').value = new_rule
def settzinfo ( self , tzinfo , start = 2000 , end = 2030 ) : def fromLastWeek ( dt ) : """
            How many weeks from the end of the month dt is, starting from 1.
            """ weekDelta = datetime . timedelta ( weeks = 1 ) n = 1 current = dt + weekDelta while current . month == dt . month : n += 1 current += weekDelta return n # lists of dictionaries defining rules which are no longer in effect completed = { 'daylight' : [ ] , 'standard' : [ ] } # dictionary defining rules which are currently in effect working = { 'daylight' : None , 'standard' : None } # rule may be based on nth week of the month or the nth from the last for year in range ( start , end + 1 ) : newyear = datetime . datetime ( year , 1 , 1 ) for transitionTo in 'daylight' , 'standard' : transition = getTransition ( transitionTo , year , tzinfo ) oldrule = working [ transitionTo ] if transition == newyear : # transitionTo is in effect for the whole year rule = { 'end' : None , 'start' : newyear , 'month' : 1 , 'weekday' : None , 'hour' : None , 'plus' : None , 'minus' : None , 'name' : tzinfo . tzname ( newyear ) , 'offset' : tzinfo . utcoffset ( newyear ) , 'offsetfrom' : tzinfo . utcoffset ( newyear ) } if oldrule is None : # transitionTo was not yet in effect working [ transitionTo ] = rule else : # transitionTo was already in effect if ( oldrule [ 'offset' ] != tzinfo . utcoffset ( newyear ) ) : # old rule was different, it shouldn't continue oldrule [ 'end' ] = year - 1 completed [ transitionTo ] . append ( oldrule ) working [ transitionTo ] = rule elif transition is None : # transitionTo is not in effect if oldrule is not None : # transitionTo used to be in effect oldrule [ 'end' ] = year - 1 completed [ transitionTo ] . append ( oldrule ) working [ transitionTo ] = None else : # an offset transition was found try : old_offset = tzinfo . utcoffset ( transition - twoHours ) name = tzinfo . tzname ( transition ) offset = tzinfo . utcoffset ( transition ) except ( pytz . AmbiguousTimeError , pytz . NonExistentTimeError ) : # guaranteed that tzinfo is a pytz timezone is_dst = ( transitionTo == "daylight" ) old_offset = tzinfo . utcoffset ( transition - twoHours , is_dst = is_dst ) name = tzinfo . tzname ( transition , is_dst = is_dst ) offset = tzinfo . utcoffset ( transition , is_dst = is_dst ) rule = { 'end' : None , # None, or an integer year 'start' : transition , # the datetime of transition 'month' : transition . month , 'weekday' : transition . weekday ( ) , 'hour' : transition . hour , 'name' : name , 'plus' : int ( ( transition . day - 1 ) / 7 + 1 ) , # nth week of the month 'minus' : fromLastWeek ( transition ) , # nth from last week 'offset' : offset , 'offsetfrom' : old_offset } if oldrule is None : working [ transitionTo ] = rule else : plusMatch = rule [ 'plus' ] == oldrule [ 'plus' ] minusMatch = rule [ 'minus' ] == oldrule [ 'minus' ] truth = plusMatch or minusMatch for key in 'month' , 'weekday' , 'hour' , 'offset' : truth = truth and rule [ key ] == oldrule [ key ] if truth : # the old rule is still true, limit to plus or minus if not plusMatch : oldrule [ 'plus' ] = None if not minusMatch : oldrule [ 'minus' ] = None else : # the new rule did not match the old oldrule [ 'end' ] = year - 1 completed [ transitionTo ] . append ( oldrule ) working [ transitionTo ] = rule for transitionTo in 'daylight' , 'standard' : if working [ transitionTo ] is not None : completed [ transitionTo ] . append ( working [ transitionTo ] ) self . tzid = [ ] self . daylight = [ ] self . standard = [ ] self . add ( 'tzid' ) . value = self . pickTzid ( tzinfo , True ) # old = None # unused? for transitionTo in 'daylight' , 'standard' : for rule in completed [ transitionTo ] : comp = self . add ( transitionTo ) dtstart = comp . add ( 'dtstart' ) dtstart . value = rule [ 'start' ] if rule [ 'name' ] is not None : comp . add ( 'tzname' ) . value = rule [ 'name' ] line = comp . add ( 'tzoffsetto' ) line . value = deltaToOffset ( rule [ 'offset' ] ) line = comp . add ( 'tzoffsetfrom' ) line . value = deltaToOffset ( rule [ 'offsetfrom' ] ) if rule [ 'plus' ] is not None : num = rule [ 'plus' ] elif rule [ 'minus' ] is not None : num = - 1 * rule [ 'minus' ] else : num = None if num is not None : dayString = ";BYDAY=" + str ( num ) + WEEKDAYS [ rule [ 'weekday' ] ] else : dayString = "" if rule [ 'end' ] is not None : if rule [ 'hour' ] is None : # all year offset, with no rule endDate = datetime . datetime ( rule [ 'end' ] , 1 , 1 ) else : weekday = rrule . weekday ( rule [ 'weekday' ] , num ) du_rule = rrule . rrule ( rrule . YEARLY , bymonth = rule [ 'month' ] , byweekday = weekday , dtstart = datetime . datetime ( rule [ 'end' ] , 1 , 1 , rule [ 'hour' ] ) ) endDate = du_rule [ 0 ] endDate = endDate . replace ( tzinfo = utc ) - rule [ 'offsetfrom' ] endString = ";UNTIL=" + dateTimeToString ( endDate ) else : endString = '' new_rule = "FREQ=YEARLY{0!s};BYMONTH={1!s}{2!s}" . format ( dayString , rule [ 'month' ] , endString ) comp . add ( 'rrule' ) . value = new_rule