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() |
Finders
v2 exposes finders through constructors that return an interface. The v1Finder / FuzzyFinder / DefaultFinder classes are described underv1 terms.
Default finder
Go NewDefaultFinder(), Rust DefaultFinder::new(). Reads the lite dataset with
the FUZZY preindex as the fast path and polygon geometry behind it. In Go the
polygon storage aliases the .tzm memory image in place: ~12 MB heap plus ~10 MB
of read-only data, 298 ns per query on an Apple M3 Max against the 2026c
dataset. In Rust the same constructor expands lite.tzb into polygons and
reports ~46 MiB peak RSS with 236 ns queries.
Embedded finder
Go NewEmbeddedFinder(), Rust EmbeddedFinder::new(). Queries the lite .tzb
in place, holding under 1 KB of heap beyond the file bytes. Query latency is
microseconds when the preindex does not cover the point. Applies to embedded
targets, memory-limited processes, and no-filesystem deployments.
Full finder
Go NewFullFinder(), Rust DefaultFinder::new_full(). Reads the full-precision
dataset expanded into memory: ~145 MB resident in Go. Results match the
unsimplified boundary data.
Data Version
Version identifier for the timezone boundary data, e.g. "2026c". TracksIANA timezone database releases viaevansiroky/timezone-boundary-builder.
Accessible at runtime via data_version() (Python), DataVersion() (Go), ordata_version() (Rust). All three tzf-dist artifacts carry the same value.
Data Format
.tzb
A TZF embedded binary file in the E profile: the compact transport format, with geometry stored as chunked zigzag-LEB128 varint streams. Consumed by every implementation. SeeEmbedded Binary Format.
.tzm
A TZF embedded binary file in the M profile: the same data with geometry stored
as one flat array of (int32, int32) pairs, so the file layout matches the
query-time structure. Read by the Go implementation; tzf-rs returnsError::Profile for such files. Generated on the host that uses it with tzf’scmd/tzb2tzm.
Profile E / Profile M
The header byte at offset 48 selects the layout of a TZF embedded binary file:0 for E (embedded, .tzb), 1 for M (memory image, .tzm). Mandatory
sections differ per profile, and cross-profile section types are rejected.
FUZZY section
Section type 10, the tile preindex stored as one sorted array of packed tile IDs
with their timezone indices. Present in all three tzf-dist artifacts. It is the
fast path for single-name queries; the multi-result API does not consult it. On
the 2026c dataset it holds 87,572 tiles, 156 of which name two timezones, in
about 880 KB.
In-place versus expanded loading
In place: the finder reads geometry out of the file bytes as each query needs
it. No decode at open, minimal heap, microsecond queries on a preindex miss.
Go NewEmbeddedFinder, x.NewFinderFromTZBReaderAt, Rust EmbeddedFinder.
Aliased in place: the M profile stores points in the query-time layout, so
ring storage points directly at the mapped bytes with no decode and no copy. The
source bytes must stay live and unmodified. Go NewFinderFromTZM.
Expanded: the file is decoded into polygon objects at open. Higher open cost
and higher resident memory, nanosecond queries. Go NewFinderFromTZB,NewFullFinder, Rust DefaultFinder.
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 tzf-rel / tzf-rel-lite repositories.
Data Files
Three files shipped by tzf-dist, all in theTZF embedded binary format 1.1 and all
carrying a FUZZY section and the same data_version:
| File | Profile | Size | Purpose |
|---|---|---|---|
lite.tzb | E | ~4 MB | Topology-simplified data; the crates.io and PyPI payload |
lite.tzm | M | ~10 MB | Memory image of the same data, read by Go NewDefaultFinder |
full.tzb | E | ~14 MB | Full-precision data; git-only in the Rust crate |
full.tzm is not published: expanding the full dataset into the M layout
produces about 67 MB.
tzf-rel / tzf-rel-lite (retired)
Previous data distribution repositories, superseded by tzf-dist. The protobuf
artifacts they carried are no longer published.
v1 terms
Terms that apply to the v1 line (tzf v1.2.x, tzf-rs 1.3.x, tzfpy 1.3.x), which is frozen at its last protobuf data release:
| Term | Meaning in v1 | v2 equivalent |
|---|---|---|
FuzzyFinder | Tile-preindex-only finder; returned no result outside covered tiles | Removed; the preindex is the fast path inside every finder |
Finder | Polygon-only finder | Default finder; the multi-result API stays polygon-exact |
DefaultFinder | Preindex with polygon fallback | Default finder, same role |
CompressedTopoTimezones | Protobuf message carrying deduplicated, polyline-encoded geometry | .tzb / .tzm |
PreindexTimezones | Protobuf message carrying the tile preindex | FUZZY section |
Algorithms & Indexing
Polygon Simplification
Applies the Ramer–Douglas–Peucker (RDP) algorithm to reduce the number of points in timezone boundary polygons. The v2 lite dataset uses an epsilon of 0.001 degrees, which caps boundary displacement at 111.2 m as certified inBORDER_CHANGE.md.
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, stored in v2 as the FUZZY section. Earth’s surface is partitioned into quadrilateral tiles at a fixed zoom level, following map tile formats. A tile enters the index only when one timezone polygon contains it completely; boundary tiles are excluded. Interior points are then resolved by tile lookup without a polygon test.
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);
in v2 it is always on, and the .tzm loader rebuilds it in parallel at open.
Section type 14 of the embedded binary format reserves a serialized form of the
index, which is not emitted today.
Algorithm details: POLYGON_INDEXING.md.
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.