Python package for finding the timezone of any point on earth (coordinates) offline
Primary timezone determination classes providing both full-featured polygon-based precision checking and lightweight approximation modes. These classes form the foundation of timezonefinder's timezone lookup capabilities.
Full-featured timezone finder with polygon-based precision checking. Uses precomputed shortcuts to reduce polygon testing while maintaining accuracy through precise point-in-polygon algorithms.
class TimezoneFinder:
def __init__(self, bin_file_location: Optional[str] = None, in_memory: bool = False):
"""
Initialize TimezoneFinder instance.
Parameters:
- bin_file_location: Path to binary data files, None for package data
- in_memory: Whether to load coordinate data into memory for faster access
"""
def timezone_at(self, *, lng: float, lat: float) -> Optional[str]:
"""
Find timezone for given coordinates, including ocean timezones.
Parameters:
- lng: Longitude in degrees (-180.0 to 180.0)
- lat: Latitude in degrees (-90.0 to 90.0)
Returns:
- Timezone name (e.g., 'Europe/Berlin', 'Etc/GMT+5') or None
"""
def timezone_at_land(self, *, lng: float, lat: float) -> Optional[str]:
"""
Find land timezone only, excluding ocean timezones.
Parameters:
- lng: Longitude in degrees (-180.0 to 180.0)
- lat: Latitude in degrees (-90.0 to 90.0)
Returns:
- Land timezone name or None for ocean locations
"""
def unique_timezone_at(self, *, lng: float, lat: float) -> Optional[str]:
"""
Find timezone if unique within the shortcut area.
Parameters:
- lng: Longitude in degrees (-180.0 to 180.0)
- lat: Latitude in degrees (-90.0 to 90.0)
Returns:
- Timezone name if unique in area, None if multiple or no zones
"""
def certain_timezone_at(self, *, lng: float, lat: float) -> Optional[str]:
"""
Find timezone with exhaustive polygon checking.
Note: Less performant than timezone_at(), only useful for custom timezone data
with incomplete coverage.
Parameters:
- lng: Longitude in degrees (-180.0 to 180.0)
- lat: Latitude in degrees (-90.0 to 90.0)
Returns:
- Timezone name if point is certainly within a polygon, None otherwise
"""@property
def nr_of_zones(self) -> int:
"""Number of timezones in the dataset."""
@property
def nr_of_polygons(self) -> int:
"""Number of boundary polygons in the dataset."""
@property
def nr_of_holes(self) -> int:
"""Number of hole polygons in the dataset."""
def zone_name_from_id(self, zone_id: int) -> str:
"""
Get timezone name from zone ID.
Parameters:
- zone_id: Zone identifier (0 to nr_of_zones-1)
Returns:
- Timezone name
Raises:
- ValueError: If zone_id is invalid
"""
def zone_id_of(self, boundary_id: int) -> int:
"""
Get the zone ID that a boundary polygon belongs to.
Parameters:
- boundary_id: ID of the boundary polygon
Returns:
- Zone ID (index in timezone_names)
Raises:
- ValueError: If zone_ids data is not available
"""
def zone_ids_of(self, boundary_ids: np.ndarray) -> np.ndarray:
"""
Get zone IDs for multiple boundary polygons.
Parameters:
- boundary_ids: Array of boundary polygon IDs
Returns:
- Array of corresponding zone IDs
"""
def zone_name_from_boundary_id(self, boundary_id: int) -> str:
"""
Get timezone name from boundary polygon ID.
Parameters:
- boundary_id: ID of the boundary polygon
Returns:
- Timezone name
"""
def coords_of(self, boundary_id: int = 0) -> np.ndarray:
"""
Get coordinates of a boundary polygon from the FlatBuffers collection.
Parameters:
- boundary_id: Index of the polygon (default: 0)
Returns:
- Array of coordinates
"""
def get_boundaries_in_shortcut(self, *, lng: float, lat: float) -> np.ndarray:
"""
Get boundary polygon IDs in the shortcut area for given coordinates.
Parameters:
- lng: Longitude in degrees (-180.0 to 180.0)
- lat: Latitude in degrees (-90.0 to 90.0)
Returns:
- Array of boundary polygon IDs
"""
def most_common_zone_id(self, *, lng: float, lat: float) -> Optional[int]:
"""
Get the most common zone ID in the shortcut area for given coordinates.
Note: Boundary polygons are sorted by zone, with zones having more polygon
coordinates coming last.
Parameters:
- lng: Longitude in degrees (-180.0 to 180.0)
- lat: Latitude in degrees (-90.0 to 90.0)
Returns:
- Most common zone ID or None if no polygons exist in shortcut
"""
def unique_zone_id(self, *, lng: float, lat: float) -> Optional[int]:
"""
Get unique zone ID in shortcut area if only one zone exists.
Parameters:
- lng: Longitude in degrees (-180.0 to 180.0)
- lat: Latitude in degrees (-90.0 to 90.0)
Returns:
- Unique zone ID or None if no polygons or multiple zones exist
"""
def inside_of_polygon(self, boundary_id: int, x: int, y: int) -> bool:
"""
Check if a point is inside a boundary polygon.
Note: Checks bounding boxes first for efficiency, then holes, then boundary.
Parameters:
- boundary_id: ID of the boundary polygon
- x: X-coordinate of the point
- y: Y-coordinate of the point
Returns:
- True if point is inside boundary polygon, False if outside or in hole
"""
@staticmethod
def using_numba() -> bool:
"""Check if Numba JIT compilation is being used."""
@staticmethod
def using_clang_pip() -> bool:
"""Check if compiled C point-in-polygon implementation is being used."""Lightweight timezone finder for fast approximations. Uses only precomputed shortcuts without polygon checking, providing the most common timezone in each area.
class TimezoneFinderL:
def __init__(self, bin_file_location: Optional[Union[str, Path]] = None, in_memory: bool = False):
"""
Initialize TimezoneFinderL instance.
Note: Inherits constructor from AbstractTimezoneFinder.
Parameters:
- bin_file_location: Path to binary data files, None for package data
- in_memory: Ignored for TimezoneFinderL, exists for compatibility
"""
def timezone_at(self, *, lng: float, lat: float) -> Optional[str]:
"""
Instantly return the most common timezone in the shortcut area.
Note: 'Most common' means the zone with boundary polygons having the most
coordinates in the corresponding shortcut area.
Parameters:
- lng: Longitude in degrees (-180.0 to 180.0)
- lat: Latitude in degrees (-90.0 to 90.0)
Returns:
- Most common timezone name in area or None if no polygons exist
"""
def timezone_at_land(self, *, lng: float, lat: float) -> Optional[str]:
"""
Find land timezone only, excluding ocean timezones.
Inherited from AbstractTimezoneFinder. Returns None when an ocean
timezone would be matched.
Parameters:
- lng: Longitude in degrees (-180.0 to 180.0)
- lat: Latitude in degrees (-90.0 to 90.0)
Returns:
- Land timezone name or None for ocean locations
"""from timezonefinder import TimezoneFinder
# Create instance
tf = TimezoneFinder()
# Single lookup
tz = tf.timezone_at(lng=13.358, lat=52.5061)
print(tz) # 'Europe/Berlin'
# Land timezone only
land_tz = tf.timezone_at_land(lng=0.0, lat=0.0)
print(land_tz) # None (ocean location)from timezonefinder import TimezoneFinder
# Load data into memory for faster repeated queries
tf = TimezoneFinder(in_memory=True)
# Check performance capabilities
print(f"Using Numba: {tf.using_numba()}")
print(f"Using C extension: {tf.using_clang_pip()}")
# Batch processing
coordinates = [
(13.358, 52.5061), # Berlin
(-74.0060, 40.7128), # New York
(139.6917, 35.6895) # Tokyo
]
for lng, lat in coordinates:
tz = tf.timezone_at(lng=lng, lat=lat)
print(f"({lat:.3f}, {lng:.3f}) -> {tz}")from timezonefinder import TimezoneFinderL
# Fast approximation without polygon checking
tfl = TimezoneFinderL()
# Quick timezone suggestion
tz = tfl.timezone_at(lng=13.358, lat=52.5061)
print(tz) # 'Europe/Berlin' (most common in area)import threading
from timezonefinder import TimezoneFinder
def worker(coordinates, results, thread_id):
# Each thread gets its own instance
tf = TimezoneFinder(in_memory=True)
for i, (lng, lat) in enumerate(coordinates):
tz = tf.timezone_at(lng=lng, lat=lat)
results[thread_id][i] = tz
# Prepare data for multiple threads
all_coords = [(lng, lat) for lng in range(-180, 180, 10)
for lat in range(-90, 90, 10)]
threads = []
results = [{} for _ in range(4)]
# Split work across threads
chunk_size = len(all_coords) // 4
for i in range(4):
start = i * chunk_size
end = start + chunk_size if i < 3 else len(all_coords)
coords_chunk = all_coords[start:end]
thread = threading.Thread(
target=worker,
args=(coords_chunk, results, i)
)
threads.append(thread)
thread.start()
# Wait for completion
for thread in threads:
thread.join()Install with Tessl CLI
npx tessl i tessl/pypi-timezonefinder