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()

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:

FileProfileSizePurpose
lite.tzbE~4 MBTopology-simplified data; the crates.io and PyPI payload
lite.tzmM~10 MBMemory image of the same data, read by Go NewDefaultFinder
full.tzbE~14 MBFull-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:

TermMeaning in v1v2 equivalent
FuzzyFinderTile-preindex-only finder; returned no result outside covered tilesRemoved; the preindex is the fast path inside every finder
FinderPolygon-only finderDefault finder; the multi-result API stays polygon-exact
DefaultFinderPreindex with polygon fallbackDefault finder, same role
CompressedTopoTimezonesProtobuf message carrying deduplicated, polyline-encoded geometry.tzb / .tzm
PreindexTimezonesProtobuf message carrying the tile preindexFUZZY 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.

Last updated on