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 (~100 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.0

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.0
File Size Uploaded Provenance Actions
polars_tzf-0.2.0.tar.gz 75.6 kB Without provenance Details for polars_tzf-0.2.0.tar.gz

Built distributions (wheels)

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

Total release size: 71.0 MB

Release files / polars_tzf-0.2.0.tar.gz

Download URL polars_tzf-0.2.0.tar.gz
Size 75.6 kB
Tags Source
SHA-256 checksum
How to use checksums
4234ef37b4e33fc1d9dde33ee0d973e55c30d19e765f9bc433cd9ec4937cff34
BLAKE2b-256 checksum
How to use checksums
3577c80f79b051a9e6b3b14c9618a370f81db24522000ff6fd50198b7f356982
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","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.0-cp310-abi3-win_arm64.whl

Download URL polars_tzf-0.2.0-cp310-abi3-win_arm64.whl
Size 8.0 MB
Tags CPython 3.10 Windows ARM64 abi3
SHA-256 checksum
How to use checksums
556b10a6e56a9170bf857a8ac5cfdad1c56ff9c5c64af97a0db46498f8ae880d
BLAKE2b-256 checksum
How to use checksums
53241de7284a9dd5b8492b60347682f89eab94090c6b5c427076f10526fd9b8d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","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.0-cp310-abi3-win_amd64.whl

Download URL polars_tzf-0.2.0-cp310-abi3-win_amd64.whl
Size 8.5 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
3afe6e5593cd3b8507eb46d4e25ca55bac97a4803189d4ad9264e7739c681338
BLAKE2b-256 checksum
How to use checksums
63a317097f9d3cd4639cf6bf27c67da6ecc5fcfcf3580a99c59c0671c0cfa247
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","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.0-cp310-abi3-musllinux_1_2_x86_64.whl

Download URL polars_tzf-0.2.0-cp310-abi3-musllinux_1_2_x86_64.whl
Size 9.7 MB
Tags CPython 3.10 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
7baf31a15f1dea312e11b33be3174aa828326c9b97ed273f5a9e09d4137e2bc9
BLAKE2b-256 checksum
How to use checksums
2254780525a457182ddfd97da040c3470b804a8edbbaafa30ad7c6b17489db70
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","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.0-cp310-abi3-musllinux_1_2_aarch64.whl

Download URL polars_tzf-0.2.0-cp310-abi3-musllinux_1_2_aarch64.whl
Size 9.4 MB
Tags CPython 3.10 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
7dfb9031adfd0173e269a772fe7774d6ec398849b755ccad581e28c447746ab2
BLAKE2b-256 checksum
How to use checksums
665adae7462ab028474ed33fcca6aa1f34be4ff26c706c9547bc3be615e352cc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","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.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL polars_tzf-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 8.9 MB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
bd181c99552ba5f30bf19987bfd705cb0b196c1864f49bd357a8124df58b4648
BLAKE2b-256 checksum
How to use checksums
c4e78dee6f6dad5955e667cab76b026a3a13cf264137cf29da3f2ec1fc5364ff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","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.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL polars_tzf-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 9.2 MB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
fed529dc3d8c0d7995dd3be8e4ddbfd49ece929098ef877e16855b94cfbf83a3
BLAKE2b-256 checksum
How to use checksums
2843e8f4878070f0110e94df130bfdfea2208e1d4390e52e653f8597191281cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","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.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL polars_tzf-0.2.0-cp310-abi3-macosx_11_0_arm64.whl
Size 8.4 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
86d214b736c4016140d76c20dfd11b174e77cabd94811ce045e07790122c9839
BLAKE2b-256 checksum
How to use checksums
11e99be2bb0b41ccddc6340788d9071806fd8c0c4f1e1c696ebbf58384e5afaf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","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.0-cp310-abi3-macosx_10_12_x86_64.whl

Download URL polars_tzf-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl
Size 8.7 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
63f9657bac2cf9dda5a0127ab5d85a147702615e2aa4fe1448e870c6ff447f72
BLAKE2b-256 checksum
How to use checksums
8c767b3d6b1c4670d0ae7ae824fc706b7ccd1057e6657eb1091160b3a2c3e27b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","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.0

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