Use coordinate-based timezone lookup for trip destinations

This commit is contained in:
Edward Betts 2026-02-26 14:57:20 +00:00
parent ec413ac310
commit 1ee1f38a99
2 changed files with 40 additions and 0 deletions

View file

@ -10,3 +10,4 @@ ephem
flask flask
requests requests
emoji emoji
timezonefinder

View file

@ -3,7 +3,9 @@
"""Web page to show upcoming events.""" """Web page to show upcoming events."""
import decimal import decimal
import functools
import hashlib import hashlib
import importlib
import inspect import inspect
import json import json
import operator import operator
@ -789,9 +791,35 @@ def _format_offset_from_bristol(offset_minutes: int) -> str:
return f"{sign}{hours:02d}:{mins:02d} vs Bristol" 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]: def get_destination_timezones(trip: Trip) -> list[StrDict]:
"""Build destination timezone metadata for the trip page.""" """Build destination timezone metadata for the trip page."""
per_location: dict[tuple[str, str], list[str]] = defaultdict(list) 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: for item in trip.accommodation + trip.conferences + trip.events:
location = item.get("location") location = item.get("location")
country = item.get("country") country = item.get("country")
@ -803,6 +831,11 @@ def get_destination_timezones(trip: Trip) -> list[StrDict]:
if isinstance(timezone_name, str): if isinstance(timezone_name, str):
per_location[key].append(timezone_name) 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 ( for field in (
"from", "from",
"to", "to",
@ -832,6 +865,12 @@ def get_destination_timezones(trip: Trip) -> list[StrDict]:
except Exception: except Exception:
continue 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: if not timezone_name:
country_timezones = pytz.country_timezones.get(country_code, []) country_timezones = pytz.country_timezones.get(country_code, [])
if len(country_timezones) == 1: if len(country_timezones) == 1: