Skip to main content

polars-tzf

License: MIT Python

Fast timezone lookup for Polars: resolve IANA timezone names from latitude/longitude coordinates or H3 cells, powered by tzf-rs.

Runs as a native Polars expression plugin written in Rust — no Python loops, no map_elements, fully parallelized by the Polars engine.

Installation

pip install polars-tzf

Or with uv:

uv add polars-tzf

Usage

import polars as pl
import polars_tzf as tzf

df = pl.DataFrame(
    {
        "place": ["Berlin", "New York City", "Tokyo", "São Paulo", "Null Island"],
        "lat": [52.5200, 40.7128, 35.6762, -23.5505, 0.0],
        "lon": [13.4050, -74.0060, 139.6503, -46.6333, 0.0],
    }
)

df.with_columns(tz=tzf.tz_name("lat", "lon"))
shape: (5, 4)
┌───────────────┬──────────┬───────────┬───────────────────┐
│ place         ┆ lat      ┆ lon       ┆ tz                │
│ ---           ┆ ---      ┆ ---       ┆ ---               │
│ str           ┆ f64      ┆ f64       ┆ str               │
╞═══════════════╪══════════╪═══════════╪═══════════════════╡
│ Berlin        ┆ 52.52    ┆ 13.405    ┆ Europe/Berlin     │
│ New York City ┆ 40.7128  ┆ -74.006   ┆ America/New_York  │
│ Tokyo         ┆ 35.6762  ┆ 139.6503  ┆ Asia/Tokyo        │
│ São Paulo     ┆ -23.5505 ┆ -46.6333  ┆ America/Sao_Paulo │
│ Null Island   ┆ 0.0      ┆ 0.0       ┆ Etc/GMT           │
└───────────────┴──────────┴───────────┴───────────────────┘

If your data is already indexed with H3 cells, resolve straight from the cell — no coordinate columns needed:

df = pl.DataFrame(
    {
        "cell": [
            "871f1d489ffffff",
            "872a1072cffffff",
            "872f5a363ffffff",
        ],
    }
)

df.with_columns(tz=tzf.tz_name_from_h3("cell"))
shape: (3, 2)
┌─────────────────┬──────────────────┐
│ cell            ┆ tz               │
│ ---             ┆ ---              │
│ str             ┆ str              │
╞═════════════════╪══════════════════╡
│ 871f1d489ffffff ┆ Europe/Berlin    │
│ 872a1072cffffff ┆ America/New_York │
│ 872f5a363ffffff ┆ Asia/Tokyo       │
└─────────────────┴──────────────────┘

It works anywhere a Polars expression works, including lazy queries:

(
    pl.scan_parquet("events.parquet")
    .with_columns(tz=tzf.tz_name("latitude", "longitude"))
    .collect()
)

API

tz_name(lat, lng) -> pl.Expr

Resolves each (lat, lng) pair to an IANA timezone name (e.g. "Europe/Berlin").

  • lat, lng — column names, expressions, or anything else Polars accepts as an expression input (IntoExpr). Both must be Float64.
  • Returns a String expression. The operation is elementwise, so it parallelizes across chunks and is safe to use in group_by/over contexts.
  • Nulls: if either coordinate is null, or no timezone matches, the result is null. Points in international waters resolve to Etc/GMT±N zones.

tz_name_from_h3(cell) -> pl.Expr

Resolves each H3 cell to the IANA timezone containing the cell's centre.

  • cell — a column of H3 indices, either as an integer (UInt64, Int64, …) or as the hex string form ("871f1d489ffffff", upper or lower case). Any other dtype raises.
  • Returns a String expression, elementwise like tz_name.
  • Nulls: null input, an index that is not a valid H3 cell, and an unparseable hex string all yield null.
  • Coarse cells: a low-resolution cell can span several timezones; you always get the one containing its centre. From resolution 7 (~1.2 km edges) downward this is effectively never ambiguous.

Performance

  • The timezone index (tzf-rs DefaultFinder) is built once per process and shared across all threads, so the one-time startup cost (~60 MB of polygon index) is amortized over the whole session.

  • Lookups run in native Rust with zero Python overhead per row. Tens of millions of rows resolve in seconds on a laptop.

  • tz_name_from_h3 memoizes on the H3 index in a thread-local cache and builds its output by gathering from a dictionary of zone names rather than writing one string per row. Both matter: on 3M rows over 50k distinct cells at resolution 9, throughput goes from ~5M rows/s (a plain per-row lookup) to ~160M rows/s. The cache needs no locking and survives across chunks and across calls on the same worker thread.

  • Throughput therefore tracks the number of distinct cells, not the row count, and it matters whether the cache is warm. Cold is a one-shot query, which pays to resolve every distinct cell; warm is what repeated calls, many row groups, or a grouped context see. Measured on 3M rows, one fresh process per row:

    distinct cells cold warm
    20,000 34 169
    120,000 25 145
    400,000 14 122
    700,000 7 16
    1,500,000 4 6

    The cache holds 2^19 (~524k) cells per worker thread, which covers a metro area at resolution 9 comfortably. Beyond that the surplus cells fall back to a full polygon lookup and throughput converges on the uncached cost — decoding the H3 index makes that floor about 25% below tz_name on raw coordinates, so if your cells are near-unique you may as well look up coordinates directly.

Reproduce with uv run python scripts/bench.py.

Accuracy

tzf-rs uses simplified timezone polygons for speed. Points very close to timezone borders (roughly within ~100 m) may be assigned to the neighboring zone. This is the right trade-off for bulk analytical workloads; if you need survey-grade precision at borders, use a full-polygon lookup instead.

Timezone data comes from timezone-boundary-builder via the tzf project.

Development

Requires Rust, Python ≥ 3.10, and uv.

git clone https://github.com/drumtorben/polars-tzf
cd polars-tzf
uv sync                          # create venv and install dev dependencies
uv run maturin develop --release # build the Rust extension into the venv

Then test your changes:

uv run python -c "
import polars as pl, polars_tzf as tzf
print(pl.select(tz=tzf.tz_name(pl.lit(52.52), pl.lit(13.405))))
"

Run the test suite:

uv run pytest

Note: always build with --release when measuring performance — debug builds are dramatically slower.

Credits

License

MIT — see LICENSE.

Metadata

Release files for polars-tzf 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for polars-tzf 0.2.1
File Size Uploaded Provenance Actions
polars_tzf-0.2.1.tar.gz 76.3 kB Without provenance Details for polars_tzf-0.2.1.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for polars-tzf 0.2.1
File Actions
polars_tzf-0.2.1-cp310-abi3-win_arm64.whl CPython 3.10 abi3 Windows ARM64 Details for polars_tzf-0.2.1-cp310-abi3-win_arm64.whl
polars_tzf-0.2.1-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details for polars_tzf-0.2.1-cp310-abi3-win_amd64.whl
polars_tzf-0.2.1-cp310-abi3-musllinux_1_2_x86_64.whl CPython 3.10 abi3 Linux musl 1.2+ x86-64 Details for polars_tzf-0.2.1-cp310-abi3-musllinux_1_2_x86_64.whl
polars_tzf-0.2.1-cp310-abi3-musllinux_1_2_aarch64.whl CPython 3.10 abi3 Linux musl 1.2+ ARM64 Details for polars_tzf-0.2.1-cp310-abi3-musllinux_1_2_aarch64.whl
polars_tzf-0.2.1-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details for polars_tzf-0.2.1-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
polars_tzf-0.2.1-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details for polars_tzf-0.2.1-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
polars_tzf-0.2.1-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details for polars_tzf-0.2.1-cp310-abi3-macosx_11_0_arm64.whl
polars_tzf-0.2.1-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details for polars_tzf-0.2.1-cp310-abi3-macosx_10_12_x86_64.whl

Total release size: 59.1 MB

Release files / polars_tzf-0.2.1.tar.gz

Download URL polars_tzf-0.2.1.tar.gz
Size 76.3 kB
Tags Source
SHA-256 checksum
How to use checksums
b49fa43b70736a30457a9b54d12e26b601314e2fc53f11845d05fa329ae10b55
BLAKE2b-256 checksum
How to use checksums
ecb6c62433349719979d407b9f3ee2223fb5db6fec4b2d6fe074a19951cc1679
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / polars_tzf-0.2.1-cp310-abi3-win_arm64.whl

Download URL polars_tzf-0.2.1-cp310-abi3-win_arm64.whl
Size 6.5 MB
Tags CPython 3.10 Windows ARM64 abi3
SHA-256 checksum
How to use checksums
37018b3438afec31d912101e58f30fa2e697900ed985dadbd5b235b34c3c6895
BLAKE2b-256 checksum
How to use checksums
4a12031fb4b32a6900945aeb9596ddce000985549ae374336497598093cc24fc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / polars_tzf-0.2.1-cp310-abi3-win_amd64.whl

Download URL polars_tzf-0.2.1-cp310-abi3-win_amd64.whl
Size 7.0 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
c9cfe9b4fd36147a01aa3f67728b2149283acd01f80b5456b05fcbc9f8707466
BLAKE2b-256 checksum
How to use checksums
712060d6ac2b1137a09f8da72aaccb37d073003a803649ec7539309154aa67bf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / polars_tzf-0.2.1-cp310-abi3-musllinux_1_2_x86_64.whl

Download URL polars_tzf-0.2.1-cp310-abi3-musllinux_1_2_x86_64.whl
Size 8.2 MB
Tags CPython 3.10 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
0407bacea3556c6ff1a017eff021bc32c681f4b76358c20327ad52584e5218f6
BLAKE2b-256 checksum
How to use checksums
8a3abb76d0139fdf9fb1d4cacdb057ffa334bf83b156ca5378189950142779d7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / polars_tzf-0.2.1-cp310-abi3-musllinux_1_2_aarch64.whl

Download URL polars_tzf-0.2.1-cp310-abi3-musllinux_1_2_aarch64.whl
Size 7.9 MB
Tags CPython 3.10 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
8ef43803cf8e00235d49b3ec82481f0761de2411ecd2439b8fef57df02ae02fd
BLAKE2b-256 checksum
How to use checksums
095b540dec91376810dba481475fa3f7b4d79a1f260b4ebad956adcc0f31babb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / polars_tzf-0.2.1-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

Download URL polars_tzf-0.2.1-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Size 7.5 MB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
a2b23338603f4e42eb32fe5a9fec66dc7a214d39b2909d918df01772d79372be
BLAKE2b-256 checksum
How to use checksums
20cfb2300a37d6d1335facb895daceee8fdfaea647f867655a4baf7b1a6c7217
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / polars_tzf-0.2.1-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl

Download URL polars_tzf-0.2.1-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
Size 7.7 MB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
55cbf39be7f2a62d40218314071bf7f70d19e17c797c42f9c1fdc66ca89f12f2
BLAKE2b-256 checksum
How to use checksums
1d2177b3c93b082c5b7affc7e3695925da216009033b1f0d0b5974ac4f0ca1ea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / polars_tzf-0.2.1-cp310-abi3-macosx_11_0_arm64.whl

Download URL polars_tzf-0.2.1-cp310-abi3-macosx_11_0_arm64.whl
Size 6.9 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
6cfe7cab7aa6c187b45026ee12a00063a92f93036348d91728f5fb7c88d67dd6
BLAKE2b-256 checksum
How to use checksums
f337d0352007bf265dec21d6a7b489d2f26f0e17f3e745dd9a8405f4c32aa546
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / polars_tzf-0.2.1-cp310-abi3-macosx_10_12_x86_64.whl

Download URL polars_tzf-0.2.1-cp310-abi3-macosx_10_12_x86_64.whl
Size 7.2 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
afe4b40284d36b5988d49cb178d5ee4d035a5874688deb42e793d29a69d7c1b2
BLAKE2b-256 checksum
How to use checksums
dbf120895bd0a59782827751c473d1147bec838e10aaf0e6b4b844b09a6a7241
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for polars-tzf 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.1 This release

9 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page