tzf-swift: a fast timezone finder for Swift

July 29, 2026 · View on GitHub

Swift FOSSA Status GitHub Tag

Note

This package ships simplified polygon data, so it is not entirely accurate around the border, but the error is small and bounded: every simplified boundary stays within ~111 m of the full-precision border. See Accuracy for measured numbers.

Usage

Add the dependency to your Package.swift file:

dependencies: [
    .package(url: "https://github.com/ringsaturn/tzf-swift.git", from: "{latest_version}")
]

Then add something like this:

import Foundation
import tzf

let finder = try DefaultFinder()

let timezone = try finder.getTimezone(lng: 116.3833, lat: 39.9167)
print("Beijing timezone:", timezone)

let timezones = try finder.getTimezones(lng: 87.5703, lat: 43.8146)
print("Multiple possible timezones:", timezones)

print("Data version:", finder.dataVersion())

if let macauGeoJSON = finder.getTimezoneGeoJSON(timezoneName: "Asia/Macau") {
  print("Asia/Macau features:", macauGeoJSON.features.count)
  print(try macauGeoJSON.toJSONString(pretty: false))
}

Output:

Beijing timezone: Asia/Shanghai
Multiple possible timezones: ["Asia/Shanghai", "Asia/Urumqi"]
Data version: 2026a/2026a
Asia/Macau features: 1
{"type":"FeatureCollection","features":[{"geometry":{"type":"MultiPolygon","coor...

Accuracy

tzf-swift bundles the topology-simplified dataset from tzf-dist: combined-with-oceans.topology.compress.topo.bin (used by Finder and DefaultFinder) and combined-with-oceans.topology.preindex.bin (used by PreindexFinder and as DefaultFinder's fast path). There is no full-precision variant in the Swift package.

The Douglas-Peucker simplification uses an epsilon of 0.001 degrees, which caps boundary displacement at roughly 111 m by construction. Measured against the full-precision 2026c dataset with tzf's internal/cmd/borderchange (spherical model, certified via Lipschitz interval subdivision):

MetricResult
Certified maximum boundary displacement111.2 m (+1.0 m tolerance)
Boundary length displaced more than 100 m0.41%
Boundary length displaced more than 500 m0%
Total mis-assigned area16,828 km² (~0.003% of Earth)
Mis-assigned area within 100 m of the true border92.8%

In other words, only queries that land within ~111 m of a timezone border can ever differ from the full-precision result, and most of that band is far narrower. If your use case is sensitive inside that band, use the full-precision finder in ringsaturn/tzf (Go) or ringsaturn/tzf-rs (Rust).

More details: BORDER_CHANGE.md in ringsaturn/tzf.

Performance

Just like tzf packages in Go/Rust/Python, the Swift version is also fast, and designed for server-side high-performance use cases.

Hardware: MacBook Pro with Apple M3 Max.

Benchmark Summary:

ImplementationTest ScaleExecution Time (ms)Success RateOperations per Second (op/sec)Time per OpMemory Usage (Peak MB)Instructions
TZF.DefaultFinder1,000,000435100%~2,298,850435 ns285~3.9 G
TZF.PreindexFinder1,000,000322~85%~3,105,590322 ns179~3.4 G
TZF.Finder1,000,000665100%~1,503,759665 ns268~5.7 G
LatLongToTimezone100,00017100%~5,882,352170 ns167~0.2 G
SwiftTimeZoneLookup.simple10,0002,932100%~3,410293.2 μs17137 G
SwiftTimeZoneLookup.lookup10,0002,975100%~3,361297.5 μs17037 G

Full benchmark results can be viewed in benchmark_baseline.txt.

Run Benchmarks

Benchmarks are isolated in the Benchmarks subpackage so the main package stays compatible with Swift 6.0 while benchmark tooling can use newer SwiftPM features.

make bench
# or:
cd Benchmarks && swift package benchmark --target TimezoneFinderBenchmarks

See Project tzf for more information.

License

This project is licensed under the MIT License. See the LICENSE file for details.

The data is licensed under ODbL-1.0 license, which compiled from https://github.com/evansiroky/timezone-boundary-builder

FOSSA Status