예제 #1
0
    def _process_eras(self, zones_map: ZonesMap) -> ZonesMap:
        """Convert various ZoneRule fields into values that are consumed by the
        ZoneInfo and ZonePolicy classes of the Arduino AceTime library.
        """
        for zone_name, eras in zones_map.items():
            for era in eras:

                # Determine the current delta seconds, based on the RULES field.
                rule_policy_name = era['rules']
                if rule_policy_name == ':':
                    delta_seconds = era['rules_delta_seconds_truncated']
                else:
                    delta_seconds = 0

                # Generate the STDOFF and DST delta offset codes.
                encoded_offset = _to_offset_and_delta(
                    offset_seconds=era['offset_seconds_truncated'],
                    delta_seconds=delta_seconds,
                    scope=self.scope,
                )
                era['offset_code'] = encoded_offset.offset_code
                era['offset_minute'] = encoded_offset.offset_minute
                era['delta_code'] = encoded_offset.delta_code
                era['delta_code_encoded'] = encoded_offset.delta_code_encoded

                # Check if STDOFF is not on 15-minute boundary
                if encoded_offset.offset_minute != 0:
                    logging.info(f"Notable zone: {zone_name}: "
                                 f"STDOFF '{era['offset_string']}' "
                                 "not on 15-minute boundary")
                    add_comment(
                        self.tresult.notable_zones, zone_name,
                        f"STDOFF '{era['offset_string']}' "
                        "not on 15-minute boundary")

                # Generate the UNTIL fields needed by Arduino ZoneProcessors
                era['until_year_tiny'] = _to_tiny_until_year(era['until_year'])
                encoded_until_time = _to_encoded_time(
                    seconds=era['until_seconds_truncated'],
                    suffix=era['until_time_suffix'],
                )
                era['until_time_code'] = encoded_until_time.time_code
                era['until_time_minute'] = encoded_until_time.time_minute
                era['until_time_modifier'] = encoded_until_time.modifier

                # Check if UNTIL is not on 15-minute boundary
                if encoded_until_time.time_minute != 0:
                    logging.info(
                        f"Notable zone: {zone_name}: "
                        f"UNTIL '{era['until_time']}' not on 15-minute boundary"
                    )
                    add_comment(
                        self.tresult.notable_zones, zone_name,
                        f"UNTIL '{era['until_time']}' not on 15-minute boundary"
                    )

                # FORMAT field for Arduino C++ replaces %s with just a %.
                era['format_short'] = era['format'].replace('%s', '%')

        return self.zones_map
예제 #2
0
    def __init__(
        self,
        invocation: str,
        tz_version: str,
        tz_files: str,
        scope: str,
        db_namespace: str,
        zones_map: ZonesMap,
        links_map: LinksMap,
        zone_ids: Dict[str, int],
        link_ids: Dict[str, int],
    ):
        self.invocation = invocation
        self.tz_version = tz_version
        self.tz_files = tz_files
        self.scope = scope
        self.db_namespace = db_namespace
        self.zones_map = zones_map
        self.links_map = links_map
        self.zone_ids = zone_ids
        self.link_ids = link_ids

        self.db_header_namespace = self.db_namespace.upper()
        self.zones_and_links = list(zones_map.keys()) + list(links_map.keys())
        self.zone_and_link_ids = zone_ids.copy()
        self.zone_and_link_ids.update(link_ids)
예제 #3
0
def _generate_fragments(zones_map: ZonesMap, links_map: LinksMap) -> IndexMap:
    """Generate a list of fragments and their indexes, sorted by fragment.
    E.g. { "Africa": 1, "America": 2, ... }
    """
    # Collect the frequency of fragments longer than 3 characters
    fragments: Dict[str, int] = Counter()
    for name in itertools.chain(zones_map.keys(), links_map.keys()):
        fragment_list = _extract_fragments(name)
        for fragment in fragment_list:
            if len(fragment) > 3:
                fragments[fragment] += 1

    # Collect fragments which occur more than 3 times.
    fragments_map: IndexMap = OrderedDict()
    index = 1  # start at 1 because '\0' is the c-string termination char
    for fragment, count in sorted(fragments.items()):
        if count > 3:
            fragments_map[fragment] = index
            index += 1
        else:
            logging.info(
                f"Ignoring fragment '{fragment}' with count {count}, too few")

    # Make sure that index is < 32, before ASCII-space.
    if index >= 32:
        raise Exception("Too many fragments {index}")

    return fragments_map
예제 #4
0
 def _generate_info_map_items(self, zones_map: ZonesMap) -> str:
     """Generate a map of (zone_name -> zoneInfo), shorted by name.
     """
     info_map_items = ''
     for zone_name, zones in sorted(zones_map.items(),
                                    key=lambda x: normalize_name(x[0])):
         info_map_items += self.ZONE_INFO_MAP_ITEM.format(
             zoneNormalizedName=normalize_name(zone_name),
             zoneFullName=zone_name)
     return info_map_items
예제 #5
0
def _generate_compressed_names(
    zones_map: ZonesMap,
    links_map: LinksMap,
    fragments_map: IndexMap,
) -> Dict[str, str]:
    compressed_names: Dict[str, str] = OrderedDict()
    for name in sorted(zones_map.keys()):
        compressed_names[name] = _compress_name(name, fragments_map)
    for name in sorted(links_map.keys()):
        compressed_names[name] = _compress_name(name, fragments_map)
    return compressed_names
예제 #6
0
def _collect_format_strings(zones_map: ZonesMap) -> IndexMap:
    """Collect the 'formats' field and return a map of indexes."""
    short_formats: Set[str] = set()
    for zone_name, eras in zones_map.items():
        for era in eras:
            format = era['format']
            short_format = format.replace('%s', '%')
            short_formats.add(short_format)

    index = 0
    short_formats_map: IndexMap = OrderedDict()
    for short_format in sorted(short_formats):
        short_formats_map[short_format] = index
        index += 1

    return short_formats_map
예제 #7
0
def _generate_zone_ids(zones_map: ZonesMap) -> Dict[str, int]:
    """Generate {zoneName -> zoneId} map."""
    ids: Dict[str, int] = {name: hash_name(name) for name in zones_map.keys()}
    return OrderedDict(sorted(ids.items()))