#!/usr/bin/python # Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import print_function import argparse import os import re import string import struct import sys from collections import namedtuple # dst-rules are formatted in 2 forms # Jordan Oct lastFri 0:00 - # US Mar Sun>=8 2:00 D # so need starting day_of_month (mday), direction (increment or decrement) # as well as dst_start or dst_end (D or S) dstrule = namedtuple('dstrule', 'dstzone ds month wday flag mday hour minute') tz_continent_list = ("Africa", "America", "Antarctica", "Asia", "Atlantic", "Australia", "Europe", "Indian", "Pacific", "Etc") tz_continent_dict = {name: index for index, name in enumerate(tz_continent_list)} # This dictionary contains all of the daylight_savings_time zones, including No-DST ('-') # Note the order of list matters, as it shouldn't change from release to release or else you'll # have a very confused watch after an upgrade until the timezone is set again. We also hardcode # certain indexes in the firmware, see the assertions below. dstzone_list = ("-", "AN", "AS", "AT", "AV", "Azer", "Brazil", "C-Eur", "Canada", "Chatham", "ChileAQ", "Cuba", "E-Eur", "E-EurAsia", "EU", "EUAsia", "Egypt", "Fiji", "Haiti", "Jordan", "LH", "Lebanon", "Mexico", "Morocco", "NZ", "Namibia", "Palestine", "Para", "RussiaAsia", "Syria", "Thule", "US", "Uruguay", "W-Eur", "WS", "Zion", "Mongol", "Moldova", "Iran", "Chile", "Tonga") dstzone_dict = {name: index for index, name in enumerate(dstzone_list)} # Make sure some of these values don't move around, because the firmware code in # fw/util/time/time.h depends on certain special case timezones having certain values (see the # DSTID_* defines). This is gross and brittle and it would be better to generate a header. # PBL-30559 assert dstzone_dict["Brazil"] == 6 assert dstzone_dict["LH"] == 20 def dstrule_cmp(a, b): """ Sort a list in the following order: 1) By dstzone 2) So that for each pair of dstzones, the 'DS' field has the following order D, S, - """ if (a.dstzone < b.dstzone): return -1 elif (a.dstzone > b.dstzone): return 1 else: if a.ds == 'D': return -1 elif b.ds == 'D': return 1 elif a.ds == 'S': return -1 elif b.ds == 'S': return 1 else: return 0 def dstrules_parse(tzfile): """Top level wrapper, greps the raw zoneinfo file Args: Returns: None """ dstrule_list = [] # struct tm->tm_mon is 0 indexed month_dict = {'Jan': 0, 'Feb': 1, 'Mar': 2, 'Apr': 3, 'May': 4, 'Jun': 5, 'Jul': 6, 'Aug': 7, 'Sep': 8, 'Oct': 9, 'Nov': 10, 'Dec': 11} # days in months for leapyear (feb is 1 day more) month_days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] # we need an 'any' wday for rules that enact on a specific day # the number picked is meaningless. Corresponds to DSTRULE_WDAY_ANY in clock.c wday_dict = {'Sun': 0, 'Mon': 1, 'Tue': 2, 'Wed': 3, 'Thu': 4, 'Fri': 5, 'Sat': 6, 'Any': 255} with open(tzfile, 'rb') as infile: lines = infile.readlines() for line_num, line in enumerate(lines): match_list = re.finditer("^Rule\s+(?P[-A-Za-z]+)\s+[0-9]+\s+max\s+-\s+" "(?P[A-Za-z]+)\s+(?P[>=A-Za-z0-9]+)\s+" "(?P