Alternatives
The position in one paragraph
timezonefinder optimises for correctness at timezone borders. It stores the boundary
polygons exactly as the source dataset provides them - every vertex of every polygon and every
hole, at ~1 cm coordinate resolution - and never simplifies them. Data Report is generated
from the packaged data and carries the current counts. Speed is the constraint that work is done
under, not the goal: the H3 spatial
index, the integer coordinate representation and the optional acceleration backends exist to make
full-resolution geometry affordable, not to shave the last microsecond off a lookup.
tzfpy makes the opposite trade, deliberately and well. It ships simplified polygons, which makes it smaller, faster to start and faster per query, at the cost of accuracy near the borders those polygons describe.
If your query points are rarely near a timezone border - coarse geofencing, analytics aggregation, high-volume classification where an occasional wrong answer within a few hundred metres of a boundary costs nothing - choose ``tzfpy``. It is a good package, it will serve you better, and its maintainer is a contributor to this one (see About). If a wrong answer at a border is a bug rather than a rounding error, that is what this package is for.
Alternative python packages
Comparison to tzfpy
tzfpy is a Python binding of the Rust package tzf-rs. Both packages use the full original
dataset (>440 timezones), so both offer full localization and historical timezone accuracy; the
difference is in what they do with that dataset’s geometry.
Feature |
timezonefinder |
tzfpy |
|---|---|---|
Implementation |
Pure Python, with an optional C extension and optional Numba JIT compilation |
Python binding of the Rust crate |
Dataset Version |
Full original dataset (>440 timezones) |
Full original dataset (>440 timezones) |
Data Representation |
Complete, non-simplified polygons at ~1 cm coordinate resolution; Data Report lists the current vertex, polygon and hole counts |
Simplified polygons, by design |
Border Accuracy |
Limited only by the source dataset |
Reduced near borders, in proportion to the simplification |
Spatial Index |
H3 hexagons at resolution 3 (~41k cells); Data Report lists the index size |
Hierarchical tree of ~80k rectangles, falling back to the simplified polygon data |
Startup Time |
Requires initialization; measured per class and mode in TimezoneFinder Initialization Performance Benchmark |
None (immediate) |
Avg. Lookup Speed |
Hundreds of thousands of queries/s on one core; Timezone Finding Performance Benchmark carries the measured figure and names the configuration behind it |
Faster per query, per a third-party benchmark on unstated hardware |
Memory Usage |
Single-digit MiB allocated by default (polygon data stays memory-mapped), an order of magnitude more with |
Not measured here |
Distribution Size |
Tens of MB per wheel, nearly all of it the packaged boundary data (Data Report lists the installed binary sizes) |
A few MB per wheel |
Build & Platform Coverage |
Builds without a Rust toolchain; the C extension is optional and its absence only costs speed |
Requires Rust to build wheels on platforms or Python versions without a prebuilt one |
Additional Features |
|
Returns GeoJSON representations of the shapes and the timezone’s indexes |
Maintainership |
Single repository |
Downstream of several repositories (tzf, tzf-rel, tzf-rs) across Go, Rust and Python |
Note
The speed row is deliberately qualitative. The two packages have never been benchmarked
under one harness, and the published figures come from different machines, different
acceleration paths and different query workloads. This project documents at length why two
measurements taken on different hardware cannot be compared - see
Benchmarking Methodology, where an unchanged lookup path spread 134-158 % across CI
runners alone - and that caveat applies just as much here. Both packages are in the same order
of magnitude and tzfpy is the faster one; anything finer would need a measurement nobody has
made.
The same applies in reverse to memory: tzfpy’s footprint has not been measured here, so the
figures linked above describe this package only and are not a claim about the comparison.
When to choose which package
Only the criteria on which the two actually differ. On dataset coverage and access to the geometry they are equivalent, so neither is a reason to pick one.
Use Case |
Recommended Package |
|---|---|
Accuracy near timezone borders |
|
Compatibility with varied Python environments and platforms |
|
Maintainability and ease of contribution |
|
Lookup throughput |
|
Initialization time |
|
Minimal distribution size |
|
Both packages will likely coexist, because these are genuinely different products.
Comparison to pytzwhere
This project was originally derived from pytzwhere
(github), which is no longer maintained and uses the
outdated tz_world dataset. A 2026 reader is not choosing between the two, but the origin story
explains the shape of everything above.
pytzwhere parses a 76 MB CSV file - floating point coordinates stored as decimal strings - fully
into memory on every startup, and computes its shortcuts from that data each time. With shapely
and numpy active it used up to 450 MB of RAM to answer a timezone lookup. That was the
reason this package exists.
Against that, the design decisions below are all the same decision made repeatedly:
32-bit integer coordinates instead of 64-bit floats. The worst-case accuracy is ~1 cm at the equator, far finer than the discrete polygons in the source data, so the extra precision was paying for nothing.
Memory-friendly binary files instead of text, read on demand rather than parsed up front. This package allocates single-digit MiB for its data structures by default, because the polygon coordinates stay memory-mapped (TimezoneFinder Memory Footprint reports every mode).
Precomputed shortcuts shipped with the package instead of rebuilt at every startup.
Two capabilities came along the way: get_geometry() for querying a timezone’s shape (a
multipolygon with holes), and optional Numba JIT compilation.