#!/usr/bin/env python3 """Regenerate ui/frame_timezones.py, the time zone -> country table usage statistics use. From the IANA tz database's zone.tab (each zone's country) and tzdata.zi (the old names that link to them), as installed on macOS and most Linux systems. It prints the old names left out because their zone is shared by several countries: check any new one, and add it to OLD_SPELLINGS if it's just an old spelling of a zone.tab zone. Run: python3 scripts/timezones.py [/usr/share/zoneinfo] """ import sys from pathlib import Path src = Path(sys.argv[1] if len(sys.argv) > 1 else '/usr/share/zoneinfo') country = {} for line in (src / 'zone.tab').read_text().splitlines(): if line and not line.startswith('#'): cc, _, zone = line.split('\t')[:3] country[zone] = cc links = {} for line in (src / 'tzdata.zi').read_text().splitlines(): if line.startswith('L '): _, target, alias = line.split() links[alias] = target def resolve(z): for _ in range(5): z = links.get(z, z) return z # An old name links to a zone with the same clocks, which can be in another country # (Africa/Asmera, Eritrea, links to Africa/Nairobi), so it only gets a country when every # zone.tab zone sharing that target is in one country. countries_of = {} for zone, cc in country.items(): countries_of.setdefault(resolve(zone), set()).add(cc) # Clock rules rather than places (EET links to Athens, WET to Lisbon): no country. GENERIC = {'CET', 'EET', 'MET', 'WET', 'EST', 'MST', 'HST', 'CST6CDT', 'EST5EDT', 'MST7MDT', 'PST8PDT'} # Places that have left zone.tab, so their target's group looks like another country's. PLACES = {'Pacific/Johnston': 'UM'} dropped = [] for alias in links: if alias in country or alias in GENERIC or alias.startswith('Etc/'): continue if alias in PLACES: country[alias] = PLACES[alias] continue ccs = countries_of.get(resolve(alias), set()) if len(ccs) == 1: country[alias] = next(iter(ccs)) else: dropped.append(alias) # Old names for a place in a zone.tab zone whose target is shared, checked by hand. OLD_SPELLINGS = { 'Africa/Asmera': 'Africa/Asmara', 'Africa/Timbuktu': 'Africa/Bamako', 'America/Coral_Harbour': 'America/Atikokan', 'America/Montreal': 'America/Toronto', 'America/Nipigon': 'America/Toronto', 'America/Thunder_Bay': 'America/Toronto', 'Canada/Eastern': 'America/Toronto', 'America/Virgin': 'America/St_Thomas', 'Antarctica/South_Pole': 'Antarctica/McMurdo', 'Asia/Rangoon': 'Asia/Yangon', 'Atlantic/Jan_Mayen': 'Arctic/Longyearbyen', 'Europe/Belfast': 'Europe/London', 'GB': 'Europe/London', 'GB-Eire': 'Europe/London', 'Iceland': 'Atlantic/Reykjavik', 'NZ': 'Pacific/Auckland', 'Pacific/Samoa': 'Pacific/Pago_Pago', 'US/Samoa': 'Pacific/Pago_Pago', 'Singapore': 'Asia/Singapore', 'US/Arizona': 'America/Phoenix', 'Pacific/Truk': 'Pacific/Chuuk', 'Pacific/Ponape': 'Pacific/Pohnpei', 'Pacific/Yap': 'Pacific/Chuuk'} for alias, zone in OLD_SPELLINGS.items(): if alias in links and zone in country: country[alias] = country[zone] dropped.remove(alias) version = (src / '+VERSION').read_text().strip() if (src / '+VERSION').exists() else 'unknown' rows = ''.join(f' {z!r}: {c!r},\n' for z, c in sorted(country.items())) out = Path(__file__).resolve().parent.parent / 'ui' / 'frame_timezones.py' out.write_text(f'''"""Time zone name -> two-letter country, from the IANA tz database {version} (zone.tab, and the old names in tzdata.zi that link to its zones). Generated by scripts/timezones.py. Zones that aren't in one country, such as UTC, aren't here.""" COUNTRY = {{ {rows}}} ''') print(f'{len(country)} zones, tz {version} -> {out}') print('no country (shared by several):', ' '.join(sorted(dropped)) or 'none')