Terminology
API Behavior
Coordinate Order
All tzf implementations use (longitude, latitude) order — consistent with GeoJSON and most geo APIs. Note that some systems (Google Maps URLs, many textbooks) use (latitude, longitude), so double-check before passing values.
Multiple Timezones
Locations near timezone boundaries may belong to more than one timezone. Use the multi-result API to retrieve all candidates:
| Language | Function |
|---|---|
| Go | GetTimezoneNames() |
| Rust | get_tz_names() |
| Python | get_tzs() |
| Swift | getTimezones() |
Finder Classes
FuzzyFinder
Uses the tile preindex only. Each tile in the index covers an area that lies entirely within a single timezone polygon.
- Point falls in a covered tile → returns the correct timezone immediately, no polygon test needed.
- Point falls outside any covered tile (near borders, coastlines, sparse regions) → returns nothing.
Results are accurate for covered tiles; the caller must handle the empty case. Fastest option (~470 ns / ~9 MB) but does not cover all coordinates.
Finder
Full polygon lookup using the topology-simplified dataset with YStripes index. Covers all global coordinates (~1–2 µs, ~66 MB).
DefaultFinder
Combines FuzzyFinder and Finder: consults the tile preindex first; if no result is returned, falls through to full polygon lookup. Delivers preindex speed for the majority of well-interior queries while remaining correct everywhere (~1 µs, ~75 MB). Recommended for most use cases.
Data Version
Version identifier for the timezone boundary data, e.g. "2025b". TracksIANA timezone database releases viaevansiroky/timezone-boundary-builder.
Accessible at runtime via data_version() (Python), DataVersion() (Go), or data_version() (Rust).
Data Files
tzf-dist
Current data distribution repository (ringsaturn/tzf-dist),
introduced in Spring 2026. Distributes processed binary data as both a Go module and a Rust crate.
Replaces the older tzf-rel / tzf-rel-lite repositories (planned for deprecation).
Data Files
Three binary files shipped by tzf-dist, all in CompressedTopoTimezones format:
| File | Size | Purpose |
|---|---|---|
combined-with-oceans.compress.topo.bin | ~17 MB | Full-precision data |
combined-with-oceans.topology.compress.topo.bin | ~5.4 MB | Topology-simplified (default) |
combined-with-oceans.topology.preindex.bin | ~2 MB | Tile preindex for FuzzyFinder |
tzf-rel / tzf-rel-lite (deprecated)
Previous data distribution repositories, now superseded by tzf-dist.
Still functional but no longer receiving updates.
Algorithms & Indexing
Polygon Simplification
Applies the Ramer–Douglas–Peucker (RDP) algorithm to reduce the number of points in timezone boundary polygons. Shrinks the raw protobuf data from ~900 MB in-memory to ~11 MB on disk, with acceptable accuracy loss (results may be incorrect within ~1 km of a border).
Topology-Aware Simplification
Enhancement to per-polygon RDP that fixes the gap/overlap problem at shared borders (tzf#183).
Shared edges between adjacent polygons are detected first, simplified once, then substituted back
into both polygons — preventing simplification from creating new gaps or overlaps.
Introduced in tzf v1.1.0 (Spring 2026). Implementation details:internal/topology/README.md.
Tile-Based Indexing
Precomputed spatial index used by FuzzyFinder. Earth’s surface is partitioned into
quadrilateral tiles at a fixed zoom level (inspired by map tile formats). A tile is added to
the index only when it is completely contained by one timezone polygon — boundary tiles are
intentionally excluded. Enables O(1) pre-filtering without polygon testing for interior points.
YStripes Index
Per-polygon spatial index ported from Josh Baker’s tidwall/tg.
Partitions each polygon’s edges into horizontal stripes; only edges in the matching stripe are
tested for a given query point. Default since tzf v1.1.0 (Go) and tzf-rs v1.2.0 (Rust).
Brings single random-city lookup to ~1 µs on modern hardware.
Algorithm details: POLYGON_INDEXING.md.
Performance
Memory Usage
Approximate figures for the Go implementation (Rust is similar):
| Mode | Memory |
|---|---|
| DefaultFinder (topology-simplified + preindex) | ~75 MB |
| Finder (topology-simplified) | ~66 MB |
| FullFinder (full-precision + preindex) | ~422 MB |
| FullFinder (full-precision only) | ~413 MB |
Rust with YStripes index adds ~30–40 MB above the no-index baseline. Full-precision mode in Rust (with YStripes) requires ~560 MB. Python (tzfpy) uses the Rust binary internally; expect ~120 MB for the default mode.
Internals
CGO vs PyO3
tzfpy originally called the Go implementation via CGO, compiled to a .so file.
Since v0.11.0 it uses PyO3 to wrap tzf-rs (Rust) instead.
PyO3 removes the need to manually manage object lifetimes across the FFI boundary,
eliminating the memory leak (tzf#63)
that CGO caused, and delivers better throughput for CPU-intensive workloads.