Ejemplo n.º 1
0
    def test_expand_date_tuple(self) -> None:
        self.assertEqual(
            (DateTuple(2000, 1, 30, 10800,
                       'w'), DateTuple(2000, 1, 30, 7200,
                                       's'), DateTuple(2000, 1, 30, 0, 'u')),
            ZoneSpecifier._expand_date_tuple(DateTuple(2000, 1, 30, 10800,
                                                       'w'),
                                             offset_seconds=7200,
                                             delta_seconds=3600))

        self.assertEqual(
            (DateTuple(2000, 1, 30, 10800,
                       'w'), DateTuple(2000, 1, 30, 7200,
                                       's'), DateTuple(2000, 1, 30, 0, 'u')),
            ZoneSpecifier._expand_date_tuple(DateTuple(2000, 1, 30, 7200, 's'),
                                             offset_seconds=7200,
                                             delta_seconds=3600))

        self.assertEqual(
            (DateTuple(2000, 1, 30, 10800,
                       'w'), DateTuple(2000, 1, 30, 7200,
                                       's'), DateTuple(2000, 1, 30, 0, 'u')),
            ZoneSpecifier._expand_date_tuple(DateTuple(2000, 1, 30, 0, 'u'),
                                             offset_seconds=7200,
                                             delta_seconds=3600))
Ejemplo n.º 2
0
    def test_Istanbul(self) -> None:
        """Europe/Istanbul uses an 'hh:mm' offset in the RULES field in 2015.
        """
        zone_specifier = ZoneSpecifier(zone_infos.ZONE_INFO_Europe_Istanbul,
                                       viewing_months=14)
        zone_specifier.init_for_year(2015)

        matches = zone_specifier.matches
        self.assertEqual(3, len(matches))

        self.assertEqual(DateTuple(2014, 12, 1, 0, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2015, 10, 25, 1 * 3600, 'u'),
                         matches[0].untilDateTime)
        self.assertEqual('EU', matches[0].zoneEra.policyName)

        self.assertEqual(DateTuple(2015, 10, 25, 1 * 3600, 'u'),
                         matches[1].startDateTime)
        self.assertEqual(DateTuple(2015, 11, 8, 1 * 3600, 'u'),
                         matches[1].untilDateTime)
        self.assertEqual(':', matches[1].zoneEra.policyName)

        self.assertEqual(DateTuple(2015, 11, 8, 1 * 3600, 'u'),
                         matches[2].startDateTime)
        self.assertEqual(DateTuple(2016, 2, 1, 0, 'w'),
                         matches[2].untilDateTime)
        self.assertEqual('EU', matches[2].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(4, len(transitions))

        self.assertEqual(DateTuple(2014, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2015, 3, 29, 3 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(2 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2015, 3, 29, 4 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2015, 10, 25, 4 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(2 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(1 * 3600, transitions[1].deltaSeconds)

        self.assertEqual(DateTuple(2015, 10, 25, 4 * 3600, 'w'),
                         transitions[2].startDateTime)
        self.assertEqual(DateTuple(2015, 11, 8, 4 * 3600, 'w'),
                         transitions[2].untilDateTime)
        self.assertEqual(2 * 3600, transitions[2].offsetSeconds)
        self.assertEqual(1 * 3600, transitions[2].deltaSeconds)

        self.assertEqual(DateTuple(2015, 11, 8, 3 * 3600, 'w'),
                         transitions[3].startDateTime)
        self.assertEqual(DateTuple(2016, 2, 1, 0, 'w'),
                         transitions[3].untilDateTime)
        self.assertEqual(2 * 3600, transitions[3].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[3].deltaSeconds)
Ejemplo n.º 3
0
    def test_Apia(self) -> None:
        """Pacific/Apia uses a transition time of 24:00 on Dec 29, 2011,
        going from Thursday 29th December 2011 23:59:59 Hours to Saturday 31st
        December 2011 00:00:00 Hours.
        """
        zone_specifier = ZoneSpecifier(zone_infos.ZONE_INFO_Pacific_Apia,
                                       viewing_months=14)
        zone_specifier.init_for_year(2011)

        matches = zone_specifier.matches
        self.assertEqual(2, len(matches))

        self.assertEqual(DateTuple(2010, 12, 1, 0, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2011, 12, 29, 24 * 3600, 'w'),
                         matches[0].untilDateTime)
        self.assertEqual('WS', matches[0].zoneEra.policyName)

        self.assertEqual(DateTuple(2011, 12, 29, 24 * 3600, 'w'),
                         matches[1].startDateTime)
        self.assertEqual(DateTuple(2012, 2, 1, 0, 'w'),
                         matches[1].untilDateTime)
        self.assertEqual('WS', matches[1].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(4, len(transitions))

        self.assertEqual(DateTuple(2010, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2011, 4, 2, 4 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(-11 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(1 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2011, 4, 2, 3 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2011, 9, 24, 3 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(-11 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[1].deltaSeconds)

        self.assertEqual(DateTuple(2011, 9, 24, 4 * 3600, 'w'),
                         transitions[2].startDateTime)
        self.assertEqual(DateTuple(2011, 12, 30, 0, 'w'),
                         transitions[2].untilDateTime)
        self.assertEqual(-11 * 3600, transitions[2].offsetSeconds)
        self.assertEqual(1 * 3600, transitions[2].deltaSeconds)

        self.assertEqual(DateTuple(2011, 12, 31, 0 * 3600, 'w'),
                         transitions[3].startDateTime)
        self.assertEqual(DateTuple(2012, 2, 1, 0, 'w'),
                         transitions[3].untilDateTime)
        self.assertEqual(13 * 3600, transitions[3].offsetSeconds)
        self.assertEqual(1 * 3600, transitions[3].deltaSeconds)
Ejemplo n.º 4
0
    def test_Simferopol(self) -> None:
        """Asia/Simferopol in 2014 uses a bizarre mixture of 'w' when using EU
        rules (which itself uses 'u' in the UNTIL fields), then uses 's' time to
        switch to Moscow time.
        """
        zone_specifier = ZoneSpecifier(zone_infos.ZONE_INFO_Europe_Simferopol,
                                       viewing_months=14)
        zone_specifier.init_for_year(2014)

        matches = zone_specifier.matches
        self.assertEqual(3, len(matches))

        self.assertEqual(DateTuple(2013, 12, 1, 0 * 3600, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2014, 3, 30, 2 * 3600, 'w'),
                         matches[0].untilDateTime)
        self.assertEqual('EU', matches[0].zoneEra.policyName)

        self.assertEqual(DateTuple(2014, 3, 30, 2 * 3600, 'w'),
                         matches[1].startDateTime)
        self.assertEqual(DateTuple(2014, 10, 26, 2 * 3600, 's'),
                         matches[1].untilDateTime)
        self.assertEqual('-', matches[1].zoneEra.policyName)

        self.assertEqual(DateTuple(2014, 10, 26, 2 * 3600, 's'),
                         matches[2].startDateTime)
        self.assertEqual(DateTuple(2015, 2, 1, 0 * 3600, 'w'),
                         matches[2].untilDateTime)
        self.assertEqual('-', matches[2].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(3, len(transitions))

        self.assertEqual(DateTuple(2013, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2014, 3, 30, 2 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(2 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2014, 3, 30, 4 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2014, 10, 26, 2 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(4 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[1].deltaSeconds)

        self.assertEqual(DateTuple(2014, 10, 26, 1 * 3600, 'w'),
                         transitions[2].startDateTime)
        self.assertEqual(DateTuple(2015, 2, 1, 0 * 3600, 'w'),
                         transitions[2].untilDateTime)
        self.assertEqual(3 * 3600, transitions[2].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[2].deltaSeconds)
Ejemplo n.º 5
0
    def test_Winnipeg(self) -> None:
        """America/Winnipeg uses 'Rule Winn' until 2006 which has an 's' suffix
        in the Rule.AT field.
        """
        zone_specifier = ZoneSpecifier(zone_infos.ZONE_INFO_America_Winnipeg,
                                       viewing_months=14)
        zone_specifier.init_for_year(2005)

        matches = zone_specifier.matches
        self.assertEqual(2, len(matches))

        self.assertEqual(DateTuple(2004, 12, 1, 0, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2006, 1, 1, 0 * 3600, 'w'),
                         matches[0].untilDateTime)
        self.assertEqual('Winn', matches[0].zoneEra.policyName)

        self.assertEqual(DateTuple(2006, 1, 1, 0 * 3600, 'w'),
                         matches[1].startDateTime)
        self.assertEqual(DateTuple(2006, 2, 1, 0 * 3600, 'w'),
                         matches[1].untilDateTime)
        self.assertEqual('Canada', matches[1].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(4, len(transitions))

        self.assertEqual(DateTuple(2004, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2005, 4, 3, 2 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(-6 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2005, 4, 3, 3 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2005, 10, 30, 3 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(-6 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(1 * 3600, transitions[1].deltaSeconds)

        self.assertEqual(DateTuple(2005, 10, 30, 2 * 3600, 'w'),
                         transitions[2].startDateTime)
        self.assertEqual(DateTuple(2006, 1, 1, 0, 'w'),
                         transitions[2].untilDateTime)
        self.assertEqual(-6 * 3600, transitions[2].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[2].deltaSeconds)

        self.assertEqual(DateTuple(2006, 1, 1, 0 * 3600, 'w'),
                         transitions[3].startDateTime)
        self.assertEqual(DateTuple(2006, 2, 1, 0, 'w'),
                         transitions[3].untilDateTime)
        self.assertEqual(-6 * 3600, transitions[3].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[3].deltaSeconds)
Ejemplo n.º 6
0
    def test_Moncton(self) -> None:
        """America/Moncton transitioned DST at 00:01 through 2006.
        """
        zone_specifier = ZoneSpecifier(zone_infos.ZONE_INFO_America_Moncton,
                                       viewing_months=14)
        zone_specifier.init_for_year(2006)

        matches = zone_specifier.matches
        self.assertEqual(2, len(matches))

        self.assertEqual(DateTuple(2005, 12, 1, 0, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2007, 1, 1, 0 * 3600, 'w'),
                         matches[0].untilDateTime)
        self.assertEqual('Moncton', matches[0].zoneEra.policyName)

        self.assertEqual(DateTuple(2007, 1, 1, 0 * 3600, 'w'),
                         matches[1].startDateTime)
        self.assertEqual(DateTuple(2007, 2, 1, 0, 'w'),
                         matches[1].untilDateTime)
        self.assertEqual('Canada', matches[1].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(4, len(transitions))

        self.assertEqual(DateTuple(2005, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2006, 4, 2, 0 * 3600 + 60, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(-4 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2006, 4, 2, 1 * 3600 + 60, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2006, 10, 29, 0 * 3600 + 60, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(-4 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(1 * 3600, transitions[1].deltaSeconds)

        self.assertEqual(DateTuple(2006, 10, 28, 23 * 3600 + 60, 'w'),
                         transitions[2].startDateTime)
        self.assertEqual(DateTuple(2007, 1, 1, 0, 'w'),
                         transitions[2].untilDateTime)
        self.assertEqual(-4 * 3600, transitions[2].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[2].deltaSeconds)

        self.assertEqual(DateTuple(2007, 1, 1, 0 * 3600, 'w'),
                         transitions[3].startDateTime)
        self.assertEqual(DateTuple(2007, 2, 1, 0, 'w'),
                         transitions[3].untilDateTime)
        self.assertEqual(-4 * 3600, transitions[3].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[3].deltaSeconds)
Ejemplo n.º 7
0
    def test_get_transition_for_datetime(self):
        zone_specifier = ZoneSpecifier(
            zone_infos.ZONE_INFO_America_Los_Angeles)

        # Just after a DST transition
        dt = datetime(2000, 4, 2, 3, 0, 0)
        transition = zone_specifier.get_transition_for_datetime(dt)
        self.assertIsNotNone(transition)

        # DST gap does not exist, but a transition should be returned.
        dt = datetime(2000, 4, 2, 2, 59, 59)
        transition = zone_specifier.get_transition_for_datetime(dt)
        self.assertIsNotNone(transition)
Ejemplo n.º 8
0
    def test_Santo_Domingo(self) -> None:
        """America/Santo_Domingo uses 2 ZoneEra changes in year 2000.
        """
        zone_specifier = ZoneSpecifier(
            zone_infos.ZONE_INFO_America_Santo_Domingo, viewing_months=14)
        zone_specifier.init_for_year(2000)

        matches = zone_specifier.matches
        self.assertEqual(3, len(matches))

        self.assertEqual(DateTuple(1999, 12, 1, 0, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2000, 10, 29, 2 * 3600, 'w'),
                         matches[0].untilDateTime)
        self.assertEqual('-', matches[0].zoneEra.policyName)

        self.assertEqual(DateTuple(2000, 10, 29, 2 * 3600, 'w'),
                         matches[1].startDateTime)
        self.assertEqual(DateTuple(2000, 12, 3, 1 * 3600, 'w'),
                         matches[1].untilDateTime)
        self.assertEqual('US', matches[1].zoneEra.policyName)

        self.assertEqual(DateTuple(2000, 12, 3, 1 * 3600, 'w'),
                         matches[2].startDateTime)
        self.assertEqual(DateTuple(2001, 2, 1, 0, 'w'),
                         matches[2].untilDateTime)
        self.assertEqual('-', matches[2].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(3, len(transitions))

        self.assertEqual(DateTuple(1999, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2000, 10, 29, 2 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(-4 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2000, 10, 29, 1 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2000, 12, 3, 1 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(-5 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[1].deltaSeconds)

        self.assertEqual(DateTuple(2000, 12, 3, 2 * 3600, 'w'),
                         transitions[2].startDateTime)
        self.assertEqual(DateTuple(2001, 2, 1, 0, 'w'),
                         transitions[2].untilDateTime)
        self.assertEqual(-4 * 3600, transitions[2].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[2].deltaSeconds)
Ejemplo n.º 9
0
    def test_normalize_date_tuple(self) -> None:
        self.assertEqual(
            DateTuple(2000, 2, 1, 0, 'w'),
            ZoneSpecifier._normalize_date_tuple(DateTuple(2000, 2, 1, 0, 'w')))

        self.assertEqual(
            DateTuple(2000, 2, 1, 0, 's'),
            ZoneSpecifier._normalize_date_tuple(
                DateTuple(2000, 1, 31, 24 * 3600, 's')))

        self.assertEqual(
            DateTuple(2000, 2, 29, 23 * 3600, 'u'),
            ZoneSpecifier._normalize_date_tuple(
                DateTuple(2000, 3, 1, -3600, 'u')))
Ejemplo n.º 10
0
    def test_Petersburg(self) -> None:
        """America/Indianapolis/Petersbug moved from central to eastern time in
        1977, then switched back in 2006, then switched back again in 2007.
        """
        zone_specifier = ZoneSpecifier(
            zone_infos.ZONE_INFO_America_Indiana_Petersburg, viewing_months=14)
        zone_specifier.init_for_year(2006)

        matches = zone_specifier.matches
        self.assertEqual(2, len(matches))

        self.assertEqual(DateTuple(2005, 12, 1, 0, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2006, 4, 2, 2 * 3600, 'w'),
                         matches[0].untilDateTime)
        self.assertEqual('-', matches[0].zoneEra.policyName)

        self.assertEqual(DateTuple(2006, 4, 2, 2 * 3600, 'w'),
                         matches[1].startDateTime)
        self.assertEqual(DateTuple(2007, 2, 1, 0, 'w'),
                         matches[1].untilDateTime)
        self.assertEqual('US', matches[1].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(3, len(transitions))

        self.assertEqual(DateTuple(2005, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2006, 4, 2, 2 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(-5 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2006, 4, 2, 2 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2006, 10, 29, 2 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(-6 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(1 * 3600, transitions[1].deltaSeconds)

        self.assertEqual(DateTuple(2006, 10, 29, 1 * 3600, 'w'),
                         transitions[2].startDateTime)
        self.assertEqual(DateTuple(2007, 2, 1, 0, 'w'),
                         transitions[2].untilDateTime)
        self.assertEqual(-6 * 3600, transitions[2].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[2].deltaSeconds)
Ejemplo n.º 11
0
    def test_Macquarie(self) -> None:
        """Antarctica/Macquarie changes ZoneEra in 2011 using a 'w' time, but
        the ZoneRule transitions use an 's' time, which happens to coincide with
        the change in ZoneEra. The code must treat those 2 transition times as
        the same point in time.
        """
        zone_specifier = ZoneSpecifier(
            zone_infos.ZONE_INFO_Antarctica_Macquarie, viewing_months=14)
        zone_specifier.init_for_year(2010)

        matches = zone_specifier.matches
        self.assertEqual(2, len(matches))

        self.assertEqual(DateTuple(2009, 12, 1, 0, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2010, 4, 4, 3 * 3600, 'w'),
                         matches[0].untilDateTime)
        self.assertEqual('AT', matches[0].zoneEra.policyName)

        self.assertEqual(DateTuple(2010, 4, 4, 3 * 3600, 'w'),
                         matches[1].startDateTime)
        self.assertEqual(DateTuple(2011, 2, 1, 0, 'w'),
                         matches[1].untilDateTime)
        self.assertEqual('-', matches[1].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(2, len(transitions))

        self.assertEqual(DateTuple(2009, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2010, 4, 4, 3 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(10 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(1 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2010, 4, 4, 3 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2011, 2, 1, 0 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(11 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[1].deltaSeconds)
Ejemplo n.º 12
0
    def _validate_test_data_for_zone(
        self,
        zone_name: str,
        items: List[TestItem],
    ) -> int:
        """Compare the given test 'items' generatd by TestDataGenerator (using
        pytz) with the expected datetime components from ZoneSpecifier. Returns
        the number of errors.
        """
        zone_info = self.zone_infos[zone_name]
        zone_specifier = ZoneSpecifier(
            zone_info_data=zone_info,
            viewing_months=self.viewing_months,
            debug=self.debug_specifier,
            in_place_transitions=self.in_place_transitions,
            optimize_candidates=self.optimize_candidates)

        num_errors = 0
        for item in items:
            if self.year is not None and self.year != item.y:
                continue

            # Print out diagnostics if mismatch detected or if debug flag given
            unix_seconds = item.epoch + SECONDS_SINCE_UNIX_EPOCH
            ldt = datetime.utcfromtimestamp(unix_seconds)
            header = (
                "======== Testing %s; at %sw; utc %s; epoch %s; unix %s" %
                (zone_name, _test_item_to_string(item), ldt, item.epoch,
                 unix_seconds))

            if self.debug_specifier:
                logging.info(header)

            try:
                info = zone_specifier.get_timezone_info_for_seconds(item.epoch)
            except Exception:
                logging.exception('Exception with test data %s', item)
                raise
            is_matched = info.total_offset == item.total_offset
            status = '**Matched**' if is_matched else '**Mismatched**'
            body = ('%s: AceTime(%s); Expected(%s)' %
                    (status, to_utc_string(info.utc_offset, info.dst_offset),
                     to_utc_string(item.total_offset - item.dst_offset,
                                   item.dst_offset)))
            if is_matched:
                if self.debug_specifier:
                    logging.info(body)
                    zone_specifier.print_matches_and_transitions()
            else:
                num_errors += 1
                if not self.debug_specifier:
                    logging.error(header)
                logging.error(body)
                zone_specifier.print_matches_and_transitions()

        return num_errors
Ejemplo n.º 13
0
    def test_Dublin(self) -> None:
        """Europe/Dublin uses negative DST during Winter.
        """
        zone_specifier = ZoneSpecifier(zone_infos.ZONE_INFO_Europe_Dublin,
                                       viewing_months=14)
        zone_specifier.init_for_year(2000)

        matches = zone_specifier.matches
        self.assertEqual(1, len(matches))

        self.assertEqual(DateTuple(1999, 12, 1, 0, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2001, 2, 1, 0, 'w'),
                         matches[0].untilDateTime)
        self.assertEqual('Eire', matches[0].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(3, len(transitions))

        self.assertEqual(DateTuple(1999, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2000, 3, 26, 1 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(1 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(-1 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2000, 3, 26, 2 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2000, 10, 29, 2 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(1 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[1].deltaSeconds)

        self.assertEqual(DateTuple(2000, 10, 29, 1 * 3600, 'w'),
                         transitions[2].startDateTime)
        self.assertEqual(DateTuple(2001, 2, 1, 0, 'w'),
                         transitions[2].untilDateTime)
        self.assertEqual(1 * 3600, transitions[2].offsetSeconds)
        self.assertEqual(-1 * 3600, transitions[2].deltaSeconds)
Ejemplo n.º 14
0
    def test_London(self) -> None:
        """Europe/London uses a EU which has a 'u' in the AT field.
        """
        zone_specifier = ZoneSpecifier(zone_infos.ZONE_INFO_Europe_London,
                                       viewing_months=14)
        zone_specifier.init_for_year(2000)

        matches = zone_specifier.matches
        self.assertEqual(1, len(matches))

        self.assertEqual(DateTuple(1999, 12, 1, 0, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2001, 2, 1, 0, 'w'),
                         matches[0].untilDateTime)
        self.assertEqual('EU', matches[0].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(3, len(transitions))

        self.assertEqual(DateTuple(1999, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2000, 3, 26, 1 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(0 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2000, 3, 26, 2 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2000, 10, 29, 2 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(0 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(1 * 3600, transitions[1].deltaSeconds)

        self.assertEqual(DateTuple(2000, 10, 29, 1 * 3600, 'w'),
                         transitions[2].startDateTime)
        self.assertEqual(DateTuple(2001, 2, 1, 0, 'w'),
                         transitions[2].untilDateTime)
        self.assertEqual(0 * 3600, transitions[2].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[2].deltaSeconds)
Ejemplo n.º 15
0
    def test_Los_Angeles(self) -> None:
        """America/Los_Angela uses a simple US rule.
        """
        zone_specifier = ZoneSpecifier(
            zone_infos.ZONE_INFO_America_Los_Angeles, viewing_months=14)
        zone_specifier.init_for_year(2000)

        matches = zone_specifier.matches
        self.assertEqual(1, len(matches))

        self.assertEqual(DateTuple(1999, 12, 1, 0, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2001, 2, 1, 0, 'w'),
                         matches[0].untilDateTime)
        self.assertEqual('US', matches[0].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(3, len(transitions))

        self.assertEqual(DateTuple(1999, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2000, 4, 2, 2 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(-8 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(0, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2000, 4, 2, 3 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2000, 10, 29, 2 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(-8 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(1 * 3600, transitions[1].deltaSeconds)

        self.assertEqual(DateTuple(2000, 10, 29, 1 * 3600, 'w'),
                         transitions[2].startDateTime)
        self.assertEqual(DateTuple(2001, 2, 1, 0, 'w'),
                         transitions[2].untilDateTime)
        self.assertEqual(-8 * 3600, transitions[2].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[2].deltaSeconds)
Ejemplo n.º 16
0
    def test_Moscow(self) -> None:
        """Europe/Moscow uses 's' in the Zone UNTIL field.
        """
        zone_specifier = ZoneSpecifier(zone_infos.ZONE_INFO_Europe_Moscow,
                                       viewing_months=14)
        zone_specifier.init_for_year(2011)

        matches = zone_specifier.matches
        self.assertEqual(2, len(matches))

        self.assertEqual(DateTuple(2010, 12, 1, 0, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2011, 3, 27, 2 * 3600, 's'),
                         matches[0].untilDateTime)
        self.assertEqual('Russia', matches[0].zoneEra.policyName)

        self.assertEqual(DateTuple(2011, 3, 27, 2 * 3600, 's'),
                         matches[1].startDateTime)
        self.assertEqual(DateTuple(2012, 2, 1, 0, 'w'),
                         matches[1].untilDateTime)
        self.assertEqual('-', matches[1].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(2, len(transitions))

        self.assertEqual(DateTuple(2010, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2011, 3, 27, 2 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(3 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2011, 3, 27, 3 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2012, 2, 1, 0 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(4 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[1].deltaSeconds)
Ejemplo n.º 17
0
    def validate_buffer_size(self) -> None:
        """Find the maximum number of actual transitions and the maximum number
        of candidate transitions required for each zone, across a range of
        years.
        """
        # map of {zoneName -> (numTransitions, year)}
        transition_stats = {}

        # If 'self.year' is defined, clobber the range of validation years.
        if self.year is not None:
            self.start_year = self.year
            self.until_year = self.year + 1
        logging.info('Calculating transitions from [%s, %s)' %
                     (self.start_year, self.until_year))

        # Calculate the buffer sizes for every Zone in zone_infos.
        for zone_name, zone_info in sorted(self.zone_infos.items()):
            if self.zone_name and zone_name != self.zone_name:
                continue
            if self.debug_validator:
                logging.info('Validating zone %s' % zone_name)

            zone_specifier = ZoneSpecifier(
                zone_info_data=zone_info,
                viewing_months=self.viewing_months,
                debug=self.debug_specifier,
                in_place_transitions=self.in_place_transitions,
                optimize_candidates=self.optimize_candidates)

            transition_stats[zone_name] = zone_specifier.get_buffer_sizes(
                self.start_year, self.until_year)

        logging.info('Zone Name: #NumTransitions (year); #MaxBufSize (year)')
        for zone_name, count_record in sorted(transition_stats.items(),
                                              key=lambda x: x[1],
                                              reverse=True):
            logging.info('%s: %d (%04d); %d (%04d)' %
                         ((zone_name, ) + count_record[0] + count_record[1]))
Ejemplo n.º 18
0
    def test_Famagusta(self) -> None:
        """Asia/Famagusta uses 'u' in the Zone UNTIL field.
        """
        zone_specifier = ZoneSpecifier(zone_infos.ZONE_INFO_Asia_Famagusta,
                                       viewing_months=14)
        zone_specifier.init_for_year(2017)

        matches = zone_specifier.matches
        self.assertEqual(2, len(matches))

        self.assertEqual(DateTuple(2016, 12, 1, 0, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2017, 10, 29, 1 * 3600, 'u'),
                         matches[0].untilDateTime)
        self.assertEqual('-', matches[0].zoneEra.policyName)

        self.assertEqual(DateTuple(2017, 10, 29, 1 * 3600, 'u'),
                         matches[1].startDateTime)
        self.assertEqual(DateTuple(2018, 2, 1, 0, 'w'),
                         matches[1].untilDateTime)
        self.assertEqual('EUAsia', matches[1].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(2, len(transitions))

        self.assertEqual(DateTuple(2016, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2017, 10, 29, 4 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(3 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2017, 10, 29, 3 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2018, 2, 1, 0 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(2 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[1].deltaSeconds)
Ejemplo n.º 19
0
    def test_Kamchatka(self) -> None:
        """Asia/Kamchatka uses 's' in the Zone UNTIL and Rule AT fields.
        """
        zone_specifier = ZoneSpecifier(zone_infos.ZONE_INFO_Asia_Kamchatka,
                                       viewing_months=14)
        zone_specifier.init_for_year(2011)

        matches = zone_specifier.matches
        self.assertEqual(2, len(matches))

        self.assertEqual(DateTuple(2010, 12, 1, 0 * 3600, 'w'),
                         matches[0].startDateTime)
        self.assertEqual(DateTuple(2011, 3, 27, 2 * 3600, 's'),
                         matches[0].untilDateTime)
        self.assertEqual('Russia', matches[0].zoneEra.policyName)

        self.assertEqual(DateTuple(2011, 3, 27, 2 * 3600, 's'),
                         matches[1].startDateTime)
        self.assertEqual(DateTuple(2012, 2, 1, 0 * 3600, 'w'),
                         matches[1].untilDateTime)
        self.assertEqual('-', matches[1].zoneEra.policyName)

        transitions = zone_specifier.transitions
        self.assertEqual(2, len(transitions))

        self.assertEqual(DateTuple(2010, 12, 1, 0, 'w'),
                         transitions[0].startDateTime)
        self.assertEqual(DateTuple(2011, 3, 27, 2 * 3600, 'w'),
                         transitions[0].untilDateTime)
        self.assertEqual(11 * 3600, transitions[0].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[0].deltaSeconds)

        self.assertEqual(DateTuple(2011, 3, 27, 3 * 3600, 'w'),
                         transitions[1].startDateTime)
        self.assertEqual(DateTuple(2012, 2, 1, 0 * 3600, 'w'),
                         transitions[1].untilDateTime)
        self.assertEqual(12 * 3600, transitions[1].offsetSeconds)
        self.assertEqual(0 * 3600, transitions[1].deltaSeconds)
Ejemplo n.º 20
0
    def _create_test_data_for_zone(
        self,
        zone_name: str,
        zone_info: ZoneInfo,
    ) -> Optional[List[TestItem]]:
        """Create the TestItems for a specific zone.
        """
        zone_specifier = ZoneSpecifier(zone_info)
        try:
            tz = pytz.timezone(zone_name)
        except pytz.UnknownTimeZoneError:
            logging.error("Zone '%s' not found in Python pytz package",
                          zone_name)
            return None

        return self._create_transition_test_items(zone_name, tz,
                                                  zone_specifier)
Ejemplo n.º 21
0
def main() -> None:
    # Configure command line flags.
    parser = argparse.ArgumentParser(description='Zone Agent.')
    parser.add_argument(
        '--viewing_months',
        help='Number of months to use for calculations (12, 13, 14, 36)',
        type=int,
        default=14)
    parser.add_argument(
        '--transition',
        help='Print the transition instead of timezone info',
        action='store_true')
    parser.add_argument(
        '--debug', help='Print debugging info', action='store_true')
    parser.add_argument(
        '--in_place_transitions',
        help='Use in-place Transition array to determine Active Transitions',
        action="store_true")
    parser.add_argument(
        '--optimize_candidates',
        help='Optimize the candidate transitions',
        action='store_true')
    parser.add_argument('--zone', help='Name of time zone', required=True)
    parser.add_argument('--year', help='Year of interest', type=int)
    parser.add_argument('--date', help='DateTime of interest')
    args = parser.parse_args()

    # Configure logging
    logging.basicConfig(level=logging.INFO)

    # Find the zone.
    zone_info = cast(ZoneInfo, zone_infos.ZONE_INFO_MAP.get(args.zone))
    if not zone_info:
        logging.error("Zone '%s' not found", args.zone)
        sys.exit(1)

    # Create the ZoneSpecifier for zone
    zone_specifier = ZoneSpecifier(
        zone_info_data=zone_info,
        viewing_months=args.viewing_months,
        debug=args.debug,
        in_place_transitions=args.in_place_transitions,
        optimize_candidates=args.optimize_candidates)

    if args.year:
        zone_specifier.init_for_year(args.year)
        if args.debug:
            logging.info('==== Final matches and transitions')
        zone_specifier.print_matches_and_transitions()
    elif args.date:
        dt: datetime = datetime.strptime(args.date, "%Y-%m-%dT%H:%M")
        if args.transition:
            transition = zone_specifier.get_transition_for_datetime(dt)
            if transition:
                logging.info(transition)
            else:
                logging.error('Transition not found')
        else:
            offset_info = zone_specifier.get_timezone_info_for_datetime(dt)
            if not offset_info:
                logging.info('Invalid time')
            else:
                logging.info(
                    '%s (%s)',
                    to_utc_string(
                        offset_info.utc_offset,
                        offset_info.dst_offset,
                    ),
                    offset_info.abbrev,
                )
    else:
        print("One of --year or --date must be provided")
        sys.exit(1)
Ejemplo n.º 22
0
    def _create_transition_test_items(
            self, zone_name: str, tz: tzinfo,
            zone_specifier: ZoneSpecifier) -> List[TestItem]:
        """Create a TestItem for the tz for each zone, for each year from
        start_year to until_year, exclusive. The following test samples are
        created:

        * One test point for each month, on the first of the month.
        * One test point for Dec 31, 23:00 for each year.
        * A test point at the transition from DST to Standard, or vise versa.
        * A test point one second before the transition.

        Each TestData is annotated as:
        * 'A': pre-transition
        * 'B': post-transition
        * 'S': a monthly test sample
        * 'Y': end of year test sample

        For [2000, 2038], this generates about 100,000 data points.
        """
        items_map: Dict[int, TestItem] = {}
        for year in range(self.start_year, self.until_year):
            # Skip start_year when viewing months is 36, because it needs data
            # for (start_year - 3), but ZoneSpecifier won't generate data for
            # years that old.
            if self.viewing_months == 36 and year == self.start_year:
                continue

            # Add samples just before and just after the DST transition.
            zone_specifier.init_for_year(year)
            for transition in zone_specifier.transitions:
                # Some Transitions from ZoneSpecifier are in previous or post
                # years (e.g. viewing_months = [14, 36]), so skip those.
                start = transition.startDateTime
                transition_year = start.y
                if transition_year != year:
                    continue

                # If viewing_months== (13 or 36), don't look at Transitions at
                # the beginning of the year since those have been already added.
                if self.viewing_months in [13, 36]:
                    if start.M == 1 and start.d == 1 and start.ss == 0:
                        continue

                epoch_seconds = transition.startEpochSecond

                # Add a test data just before the transition
                test_item = self._create_test_item_from_epoch_seconds(
                    tz, epoch_seconds - 1, 'A')
                self._add_test_item(items_map, test_item)

                # Add a test data at the transition itself (which will
                # normally be shifted forward or backwards).
                test_item = self._create_test_item_from_epoch_seconds(
                    tz, epoch_seconds, 'B')
                self._add_test_item(items_map, test_item)

            # Add one sample test point on the first of each month
            for month in range(1, 13):
                tt = DateTuple(y=year, M=month, d=1, ss=0, f='w')
                test_item = self._create_test_item_from_datetime(tz,
                                                                 tt,
                                                                 type='S')
                self._add_test_item(items_map, test_item)

            # Add a sample test point at the end of the year.
            tt = DateTuple(y=year, M=12, d=31, ss=23 * 3600, f='w')
            test_item = self._create_test_item_from_datetime(tz, tt, type='Y')
            self._add_test_item(items_map, test_item)

        # Return the TestItems ordered by epoch
        return [items_map[x] for x in sorted(items_map)]