diff --git a/requirements.txt b/requirements.txt index 3ed2d57..016dc03 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,3 +10,4 @@ ephem flask requests emoji +timezonefinder diff --git a/web_view.py b/web_view.py index 3147883..1755252 100755 --- a/web_view.py +++ b/web_view.py @@ -3,7 +3,9 @@ """Web page to show upcoming events.""" import decimal +import functools import hashlib +import importlib import inspect import json import operator @@ -789,9 +791,35 @@ def _format_offset_from_bristol(offset_minutes: int) -> str: return f"{sign}{hours:02d}:{mins:02d} vs Bristol" +def _timezone_from_coordinates(latitude: float, longitude: float) -> str | None: + """Resolve IANA timezone name from coordinates.""" + timezone_finder = _get_timezone_finder() + if timezone_finder is None: + return None + + tz_name = timezone_finder.timezone_at(lng=longitude, lat=latitude) + return tz_name if isinstance(tz_name, str) else None + + +@functools.lru_cache(maxsize=1) +def _get_timezone_finder() -> typing.Any: + """Get timezone finder instance if dependency is available.""" + try: + timezonefinder_module = importlib.import_module("timezonefinder") + except ModuleNotFoundError: + return None + + timezone_finder_cls = getattr(timezonefinder_module, "TimezoneFinder", None) + if timezone_finder_cls is None: + return None + + return timezone_finder_cls() + + def get_destination_timezones(trip: Trip) -> list[StrDict]: """Build destination timezone metadata for the trip page.""" per_location: dict[tuple[str, str], list[str]] = defaultdict(list) + location_coords: dict[tuple[str, str], tuple[float, float]] = {} for item in trip.accommodation + trip.conferences + trip.events: location = item.get("location") country = item.get("country") @@ -803,6 +831,11 @@ def get_destination_timezones(trip: Trip) -> list[StrDict]: if isinstance(timezone_name, str): per_location[key].append(timezone_name) + latitude = item.get("latitude") + longitude = item.get("longitude") + if isinstance(latitude, (int, float)) and isinstance(longitude, (int, float)): + location_coords[key] = (float(latitude), float(longitude)) + for field in ( "from", "to", @@ -832,6 +865,12 @@ def get_destination_timezones(trip: Trip) -> list[StrDict]: except Exception: continue + if not timezone_name and key in location_coords: + latitude, longitude = location_coords[key] + coordinate_timezone = _timezone_from_coordinates(latitude, longitude) + if coordinate_timezone: + timezone_name = coordinate_timezone + if not timezone_name: country_timezones = pytz.country_timezones.get(country_code, []) if len(country_timezones) == 1: