Skip to content

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:

LanguageFunction
GoGetTimezoneNames()
Rustget_tz_names()
Pythonget_tzs()
SwiftgetTimezones()

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:

FileSizePurpose
combined-with-oceans.compress.topo.bin~17 MBFull-precision data
combined-with-oceans.topology.compress.topo.bin~5.4 MBTopology-simplified (default)
combined-with-oceans.topology.preindex.bin~2 MBTile 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):

ModeMemory
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.

Last updated on