Changelog

X.X.X (unreleased)

  • fixed a BufferError: cannot close exported pointers exist raised during resource cleanup in file mode (in_memory=False). A coordinate array obtained from coords_of() is a zero-copy view onto the memory-mapped file, and mmap.close() refuses to unmap while one is alive, so an array outliving its TimezoneFinder raised on cleanup. The mapping now stays valid instead of leaving the views dangling, and FileCoordAccessor.cleanup() releases its own references so the deferred close happens as soon as the last view is dropped. The accessor must not be used after cleanup()

  • polygon coordinates are now stored one axis at a time in the packaged coordinates.fbs files - all x values followed by all y values per polygon, instead of interleaved. The point in polygon test scans a single axis per iteration, so contiguous per-axis blocks halve the cache lines it touches: ~1.6x faster on a median polygon and ~2.5x faster on the largest ones via the C extension, 14-25% faster via Numba. The bundled data was regenerated accordingly, and the layout is described in the data format documentation

  • the packaged coordinates.fbs files now carry a FlatBuffers file identifier and a layout version recording the coordinate encoding, and TimezoneFinder raises a ValueError naming the offending file when it does not match - previously such a directory was read without complaint and produced wrong timezones. If you compile your own data and point bin_file_location at it, regenerate it once with scripts/file_converter.py, since the coordinate layout changed in this release. The marker tracks the encoding rather than the package version, so this is not a per-release obligation

  • the memory footprint of every finder configuration is now measured and published in a new memory report, separating what a configuration allocates (tracemalloc) from what it makes resident (RSS, which additionally counts memory-mapped pages). The distinction is the point: the default mode maps the coordinate data instead of reading it, so it allocates an order of magnitude less than the in-memory mode, and only the pages a lookup actually touches become resident. This replaces documentation claiming a 40MB process ceiling and a 41MB data directory, both long out of date

  • restructured README.rst. It opens with the project banner and a one-sentence statement of what the package is for, then the badges, then the quick guide - and adds three short sections that were missing entirely: How it works (the lookup pipeline and the no-simplification trade-off), Performance (a concrete throughput figure with its configuration named, the three point-in-polygon backends and the pure-Python fallback), and Engineering notes linking the architecture, data format and benchmarking methodology pages. The maintainers-wanted notice moves from the first heading after the intro into a new Contributing section at the bottom, which also links CONTRIBUTING.md for the first time. The badge block is corrected along the way: the code style: black badge named a formatter this project has never used and is replaced by ruff, and a supported-Python-versions badge was added. The banner is referenced by absolute URL, since PyPI serves the long description without the repository and a docs/… path renders as a broken image there

  • rewrote the package comparison page. It now states its position in prose before the first table - border correctness is what this package optimises for, speed is the constraint that work happens under - and says plainly when tzfpy is the better choice. Every quantitative cell names what it measures and links its source, and the speed row is deliberately qualitative on both sides, with a note explaining that the two packages have never been benchmarked under one harness. The decision table drops the rows on which the two packages do not differ

  • two new documentation pages: Architecture describes the lookup pipeline, the three point-in-polygon backends and the memory modes, and states the ceilings this package deliberately does not exceed - unsimplified geometry, ~1 cm coordinate resolution, no general-purpose spatial code. Benchmarking Methodology documents how the published numbers are produced and what they can and cannot tell you: ubuntu-latest pins the runner image and not the CPU, which is why a pull request is measured against its own merge base on the same runner and why every alert threshold is derived from measured noise. It was previously addressed only to contributors, in the second half of CONTRIBUTING.md, which now keeps the operational instructions and links to it

  • the H3 resolution choice in the data format documentation is no longer asserted to “offer a good balance” but reports the study behind it (prototypes/single_resolution_bench.py): resolution 3 keeps the hybrid index at a small fraction of the packaged polygon data, while resolution 4 would exceed 10 % of it for gains that do not justify the increase

  • the hand-written documentation no longer restates exact figures that belong to the generated pages - dataset vertex, polygon and hole counts, index and distribution sizes, memory footprints, lookup throughput. Those change with every data update and with code that shifts a footprint, which silently left the copies wrong: the memory figures had already gone stale in four places. The prose now states the magnitude that survives a data update and links the data report or the relevant benchmark report, which are regenerated from the packaged data and are always current

  • the hybrid shortcut loader no longer keeps the entire shortcut binary in memory. The polygon id arrays it returns were zero-copy views onto the ~1.5 MB file buffer, so ~47 KB of live data pinned the whole thing for the lifetime of every TimezoneFinder / TimezoneFinderL instance. They are now disjoint read-only slices of a single compact array, cutting the shortcut mapping’s footprint from ~7.4 MB to ~4.7 MB per instance, and every finder’s resident set by ~2 MB, at unchanged initialisation time - which matters most for concurrent workloads, where the recommended one-instance-per-thread pattern multiplied the waste

Internal:

  • added DATA_VERSION file tracking which timezone-boundary-builder release the packaged data was generated from, written automatically by the data update script after a successful parse. Thanks to Lucas Hemkemeier for the PR #429

  • the packaged data now updates itself: a weekly workflow compares DATA_VERSION against the latest timezone-boundary-builder release, regenerates the data and opens a ready-to-review update PR, which is merged and released automatically once its CI passes - the version tag is pushed with a GitHub App token, since the default one would not trigger the release pipeline. On failure it labels the PR automation-failed, notifies the maintainer, and falls back to the previous notification issue (issues #273 and #167). Thanks to Lucas Hemkemeier for the PRs #434 and #436

  • update_data.sh (renamed from parse_data.sh) is CI-ready: interactive prompts replaced by flags (--dataset=full|same-since-now, --with-oceans, --rm-tmp), the changelog entry for a data update generated automatically, no redundant tox run, and a make reports at the end so the benchmark and data reports cannot go stale relative to the data an update PR ships. A standalone make parse/make testparse still needs a manual make reports (issue #167). Thanks to Lucas Hemkemeier for the PRs #432 and #434

  • added property-based tests (hypothesis) for coordinate validation (solves issue #143). Thanks to Lu Yicheng for the PRs #431 and #433

  • consolidated the three overlapping coding-agent instruction files into one canonical source: CLAUDE.md now holds all guidance, Agents.md is renamed to AGENTS.md and reduced to a pointer stub, and the legacy .cursorrules is replaced by .cursor/rules/repo-instructions.mdc (also a pointer stub), removing the drift risk of maintaining three near-duplicate copies

  • replaced the hand-rolled timeit timing in scripts/check_speed_*.py with pytest-benchmark suites under benchmarks/, excluded from make test/make testall via testpaths. Both they and the memory harness run over deterministic committed fixtures (tests/fixtures/benchmarks/), so two runs of the same commit execute the exact same workload; the loader rejects fixtures that no longer match the checkout. Measurement and rendering are decoupled, so docs/benchmark_results_*.rst can be regenerated from a stored JSON without re-measuring. Run via make speedtest, make benchmarks, make memory or make reports

  • memory is measured by its own harness (scripts/measure_memory.py, make memory) rather than by pytest-benchmark, which times code and would have its timings distorted by allocation tracking. It emits pytest-benchmark-shaped JSON, so the existing normalisation, noise and comparison tooling works on it unchanged given a --metric. tests/test_memory_footprint.py fails if a mode’s allocation leaves its order of magnitude - the regression that would make in_memory=False stop being the low-memory option

  • added continuous benchmarking on CI (solves issue #150), deliberately kept out of the release pipeline in build.yml: the tracked core subset and the memory harness run on every pull request and every push to master, publishing trend charts to gh-pages and posting a same-runner base/head comparison on the pull request. A pull request is measured against its own merge base in the same job rather than against a stored baseline, because runs-on: ubuntu-latest pins the runner image and not the CPU. The measurement design, the tracked estimator and every alert threshold are documented in the new benchmarking methodology page. The measuring job holds no write permissions and no secrets, so branch and fork pull requests behave identically; the comment is posted by a separate, privileged workflow via workflow_run

  • guarded the benchmark plumbing against silent drift: tests/test_benchmark_names.py and tests/test_memory_metric_names.py pin the node ids and metric names that join a measurement to its chart history, so a rename fails loudly instead of starting an empty chart beside the orphaned old one; tests/test_benchmark_workflows.py asserts that the constants duplicated across the two workflows agree, where a one-sided edit previously had no failure mode at all, and that the cross-machine trend chart cannot creep back into the pull request comparison; and docs/benchmark_results_*.rst carry a provenance stamp naming the fixture and timezone data versions they were measured against

  • every generator now emits output that is already pre-commit-clean, so regenerating and diffing compares like with like: write_json sorts keys the way pretty-format-json does, and neither scripts/reporting.py nor BenchmarkReporter emits trailing whitespace on empty cells or a trailing blank line. Previously every make parse/make reports left its outputs looking modified until the hooks had run, which masked whether a regeneration had actually changed anything

  • every generated benchmark report now opens with its headline figure and the configuration behind it, above the tables: how long a lookup takes and how many per second, the per-check cost across polygon sizes, construction time, footprint per mode - all derived from the same parsed JSON as the tables, never hardcoded. The banner beneath states which acceleration path and platform produced the numbers, and says whether that is the configuration CI tracks: the committed reports are rendered from a developer machine with Numba enabled, while CI measures the C extension without Numba, so their figures were never comparable to the trend chart and now say so

  • make flatbuf no longer overwrites hand-maintained __init__.py files. flatc derives its output path from the schema namespace and writes an empty __init__.py at every level of it, so generating in place wiped the __all__ in timezonefinder/__init__.py - the whole public API. The target now generates into a scratch tree, copies back only the generated packages, and runs the formatters on the result so a regeneration diff shows the codegen change rather than formatting churn

  • mypy now type-checks the whole package except the flatc-generated bindings. ignore_errors previously covered roughly 800 lines of hand-written code as well, where a blatantly wrong return type still reported “Success”; they all pass once the exemption is lifted, bar two genuine findings now fixed. tests/test_mypy_config.py keeps the list restricted to generated code, so silencing a module is a reviewed decision rather than a one-line edit

  • the hybrid shortcut reader and writer now select their FlatBuffers schema from a single registry (SHORTCUT_SCHEMAS in timezonefinder/flatbuf/io/hybrid_shortcuts.py) instead of dispatching on the zone id width in three places, each keyed differently. One ShortcutSchema per width owns the width, the file name, the uintN marker and the maximum zone id, which were previously written down across five places with nothing tying them together. Verified behaviour-preserving down to the bytes: re-writing the shipped shortcut binary produces a byte-identical file

  • removed constructs that provably did nothing, and gave two vacuous tests real assertions. Most consequentially, four __slots__ entries were declared but assigned by nothing, which silently re-permitted the very attributes __slots__ is there to forbid - assigning those names now raises AttributeError, and test_declared_slots_are_assigned keeps the list honest

  • get_corrected_hex_boundaries exists once again. An earlier refactor left two verbatim copies of the antimeridian and pole clipping rules with nothing keeping them in sync; the copy without callers is deleted, and the survivor is now covered by tests/hex_utils_test.py - it previously had no direct tests at all. scripts/configs.py no longer declares MAX_LAT/MAX_LNG as a second pair of names for timezonefinder.configs’s constants

  • added a code-quality-pass coding-agent skill (.claude/skills/, the only tracked part of .claude/) driving one autonomous internal-quality pass: triage, a single-theme refactor that must not change observable behaviour, the full verification gate and a pull request against master. Findings accumulate in potential-improvements.md, a committed ledger every pass reads before touching a source file; entries carry a status, so a candidate already shipped or rejected is not raised again and a pass that finds nothing worth changing still leaves its triage behind

  • plans/ is git-ignored alongside tmp/ and .venv/: implementation plans written while working on a change are local scratch, and leaving the directory untracked-but-unignored made it noise in every git status and a candidate for an over-broad git add

  • failing paths now report the input that failed. tests/auxiliaries.py’s run_command assembled the child’s stdout and stderr into a message and then raised a fresh CalledProcessError that never used it, with from None discarding the original too, so a packaging failure under make testint reported an exit code and nothing about the cause; it now echoes the captured streams and re-raises the original exception with its traceback intact. scripts/reporting.py passes the coordinate file paths into get_polygon_collection, whose optional file_path exists precisely so an incompatible-layout ValueError can say which of the two files was stale - make reports against an outdated data directory previously could not. Boundaries.overlaps names the type it rejected instead of raising a bare TypeError, and the RuntimeError for missing original_polygons names the polygon and resolution it was computing. The two re-raises ruff flags under B904 now say from None explicitly, so a deliberately dropped exception chain is distinguishable from a forgotten one, and timezonefinder/command_line.py drops FileNotFoundError from an except tuple that already caught its base class OSError. tests/test_error_diagnostics.py pins what each of these messages must contain

8.2.5 (2026-07-11)

  • updated the data to 2026c

8.2.4 (2026-05-01)

  • added manylinux_2_28_x86_64 wheel to releases, fixing the fallback to version 6.0.1 when pip resolves with --platform manylinux_2_28_x86_64 (Python 3.14 + numpy 2.4). . Thanks to theirix for the PR #420

8.2.3 (2026-04-30)

  • updated the data to 2026b

  • added examples and documentation for using parallel processing with the timezonefinder libary.

Internal:

  • reduced code duplication in coordinate validators: extracted common validation logic into a reusable _validate_coordinate() helper function

  • improved error handling and warning emission during __del__ resource cleanup

  • refactored command_line.py for improved maintainability:
    • decomposed monolithic main() function into focused, independently testable components: _parse_arguments(), _lookup_timezone(), and _print_lookup_details()

    • reduced cyclomatic complexity and improved separation of concerns

  • modernized codebase with Python 3.11+ features and best practices:
    • migrated from typing module imports to collections.abc for Iterable and Callable

    • added Self type annotation for context manager protocol

    • replaced conditional dispatches with match/case statements for improved clarity and maintainability

  • using python 3.10+ type hints. Thanks to Marco Barbosa

  • enhanced test coverage:
    • added 8 comprehensive thread safety tests for concurrent singleton initialization

    • added 37 coordinate validation tests covering edge cases (NaN, Inf, boundary values)

  • comprehensive code quality improvements for production-grade stability:
    • improved exception handling: replaced bare except clauses with specific exception types (FileNotFoundError, OSError, IOError), added proper exception chaining via from e

    • enhanced type hints: added complete type annotations to public APIs, resolved type checking issues with mypy

    • enriched documentation: added comprehensive module and function docstrings with parameter descriptions, return types, error documentation, and usage examples

    • explicit API exports: added __all__ declarations to utils.py, zone_names.py, global_functions.py, and configs.py for clearer public API surface

    • improved error messages: replaced vague errors with specific context including valid ranges, expected values, and data locations

    • fixed deprecated patterns: updated tempfile API usage to modern context managers, fixed import ordering (stdlib first)

    • enhanced validation: added type checking for string inputs, better coordinate validation with clear error messages

8.2.2 (2026-03-26)

  • updated the data to 2026a

8.2.1 (2026-01-10)

  • updated the data to 2025c

  • require numpy >=2 following the official NumPy Deprecation Policy

  • dropped official support for Python 3.9 and 3.10, due to NumPy dropping support for these versions.

Internal:

  • Introduced slow test marker for computationally expensive tests to improve CI performance and local development workflow. Updated CI configuration, tox environments, Makefile targets, and documentation accordingly. Thanks to Chase Horton for the PR.

  • enabled Numba tests for Python 3.13 and 3.14.

8.2.0 (2025-12-23)

  • Reverted to the full timezone dataset: Starting from this release, timezonefinder uses the full original timezones-with-oceans dataset instead of the reduced timezones-now dataset. This restores access to all >440 original timezone names, providing full localization capabilities and historical timezone accuracy. The reduced dataset (with ~90 timezones) is still available via the parse_data.sh script for users who prefer the smaller memory footprint. Due to the discussion in GitHub Issue #363

  • Improved error handling for resource cleanup. Thanks to Dave Tapley for the PR #375.

  • Bug fixed where on termination we may hit an exception attempting to close resources in FileCoordAccessor. Thanks to David Park for the PR #377.

  • Made CFFI extension builds fallible, allowing the build process to continue even if C extension compilation fails. Thanks to theirix for the PR #369.

  • Added Python 3.14 to the supported test matrix (tox + GitHub Actions).

8.1.0 (2025-09-22)

  • add the support of using the TimeZonefinder class instances as context managers. added a basic usage examples

  • note that the performance of certain_timezone_at() degraded drastically, since now many more polygons will be checked with an expensive point-in-polygon algorithm. consider using timezone_at() or timezone_at_land() instead.

  • introduced hybrid shortcut index structure that combines the functionality of separate shortcuts and unique shortcuts into a single optimized data structure, improving performance and reducing memory usage

  • zone id storage now defaults to uint8 and can be overridden via --zone-id-dtype/TIMEZONEFINDER_ZONE_ID_DTYPE when recompiling binaries

  • relax cffi upper bound to allow the 2.x series so downstream packages pinning cffi>=2.0 resolve cleanly

  • scripts/reporting.py can now be executed as a standalone script to generate data reports from binary files independent from file_converter.py

  • the check_speed_*.py scripts now generates a detailed performance reports in reStructuredText format automatically included into documentation

Internal:

  • using abi3 (aka Python limited API) wheels to avoid a combinatory explosion with Python version. It allows the use of a single Python 3.9 base and building future-proof wheels. Thanks to theirix

  • using pydantic to validating and parsing the GeoJSON dataset. Thanks to ARYAN RAJ for the PR.

  • refactored file_converter.py to improve code quality. Thanks to Pratyush Kumar for the PR.

  • consolidated shortcut data structures: replaced shortcuts.fbs file with hybrid_shortcuts_uint8.fbs (or hybrid_shortcuts_uint16.fbs) file that stores both polygon lists and direct zone IDs using the minimal dtype for zone IDs.

8.0.0 (2025-08-11)

  • starting from this release, timezonefinder uses the reduced timezones-now dataset version (cf. GitHub Discussion )

  • in this dataset version, all timezones which agree on timekeeping methods as of the release date of the dataset, are merged into one zone (cf. Dataset Documentation ). This results in a reduced set of ~90 timezones instead of >440 timezones and a reduced memory footprint of the package.

  • If you used timezonefinder for localisation beyond the timezone behavior, it might become necessary for you to individually parse the full original dataset version using the parse_data.sh script.

  • extended the parse_data.sh script to support downloading the timezones-now Dataset

  • adapted tests to the reduced dataset version

7.0.2 (2025-08-06)

  • exclude tests package closing issue #330

7.0.1 (2025-07-24)

  • hit PyPI project size limit. triggering re-upload to fix missing sdist in 7.0.0 release.

  • deleted all PyPI releases up to version 3.4.2 (last version supporting python 2.7) to free up project space

7.0.0 (2025-07-21)

  • Simplified API for end-users, reducing redundant code

  • Added global functions that use a shared TimezoneFinder instance:
    • timezone_at

    • timezone_at_land

    • unique_timezone_at

    • certain_timezone_at

    • get_geometry

  • Documented usage and warned about thread safety considerations for global functions

  • Updated command line interface to use global functions where appropriate

  • breaking API Changes: clarified naming. renamed “boundary” to “bbox”. renamed “polygon” to “boundary”. boundaries (the outer polygon defining part of a timezone) and holes are both polygons so hence the name “polygon” is ambiguous.

6.6.3 (2025-07-21)

  • when in_memory=True, all polygon numpy arrays are constructed once during startup rather than repeatedly on demand. This should significantly improve performance for applications that make frequent polygons queries.

  • Created a coord_accessors.py module for abstracting access to polygon coordinates, allowing for both in-memory and file-based access.

  • added auto-generated data report to the documentation. thanks to ARYAN RAJ for the PR.

6.6.2 (2025-07-19)

  • hotfix missing hole_registry.json in the distributions

  • added integration tests in CI/CD. Thanks to theirix

6.6.1 (2025-07-18)

  • hotfix missing flatbuf module in the distributions

  • added tests for checking the content of the distributions

6.6.0 (2025-07-17)

  • major internal refactoring without breaking API changes. improvements for performance and code quality

  • use flatbuffer binary files for storing the polygon coordinate data and the shorcuts (spatial h3 index) in binary format. removed any custom code for reading and writing binary files (e.g. seek operations)

  • documented the binary format in the documentation

  • grouping all data files into a single “data” folder

  • added a new class PolygonArray to abstract away handling binary data of multiple polygons

  • separate binary data storage folders for polygon boundaries and holes. handling both with the PolygonArray class

  • parameterised location tests

  • improved CLI code quality suppressing any output. added nicer output in verbose mode

  • dropped support for python 3.8 (reached the end of life). thanks to ARYAN RAJ for the PR.

  • added support for official for python 3.12

  • added usage example scripts

  • switched from poetry to uv for dependency management and packaging. Thanks to theirix

6.5.9 (2025-03-25)

  • updated the timezone boundary data to version 2025b. Thanks to WestonReed

6.5.8 (2025-01-21)

  • updated the data to 2025a

  • internal: updated file_converter.py for h3>=4

6.5.7 (2024-12-02)

  • improved error handling to catch ValueError: not enough values to unpack (Issue #209)

6.5.6 (2024-12-02)

  • add musllinux Wheels for Linux. Thanks to Pxli9130

6.5.5 (2024-11-20)

6.5.4 (2024-10-22)

6.5.3 (2024-09-16)

  • updated the data to 2024b.

  • refactored C lang point in polygon utils

6.5.2 (2024-06-17)

  • added support for numpy>=2.0 (fixes issue #234)

6.5.1 (2024-06-14)

  • added support for cibuildwheel: publish wheels including the native C extension. GHA CI/CD pipeline creates sdist (no binaries inside) and a bunch of binary wheels with a prebuilt clang-pip extension for each python version. Thanks to theirix

6.5.0 (2024-03-14)

  • updated the data to 2024a.

internal:

  • use ruff linter in pre-commit hook

  • make dependency specifications less strict

6.4.1 (2024-02-08)

  • added official support for python 3.8 again, by specifying numba as multiple constraint dependency

internal:

  • added unit tests for polygon boundary binary reading

6.4.0 (2024-02-02)

  • added python 3.12 support (supported by numba since release 0.59.0), Closes #208

  • dropped official support for python 3.8, because the optional dependency numba requires python 3.9. this package might still work with python 3.8, but it is not tested anymore.

6.3.0 (2024-02-01)

  • updated the data to 2023d.

internal:

  • added docstrings. Thanks to Tyler Huntley

  • automatically skip GitHub actions publishing when the version already exists. useful for minor improvements without publishing a version. build would always fail otherwise

  • enable tests for python 3.11 with numba

  • enable tests for python 3.12

  • added tests for generating the documentation

  • use poetry dependency group specification (closing #199)

6.2.0 (2023-03-26)

  • updated the data to 2023b.

6.1.10 (2023-03-22)

  • added a pytz extra for easily maintaining compatibility

  • improved documentation

6.1.9 (2022-12-06)

  • updated the data to 2022g.

6.1.8 (2022-11-25)

  • pumped h3 dependency to >=3.7.6,<4 to support python 3.11 (FIX #170)

  • added python 3.11 tests (not yet supporting numba)

6.1.7 (2022-11-20)

  • updated the data to 2022f.

  • pinning dependencies more strictly

6.1.6 (2022-10-30)

  • updated the data to 2022d.

6.1.5 (2022-10-25)

  • updated the data to 2022b.

  • logging build failures with warnings

6.1.4 (2022-10-23)

  • more permissive optional Numba dependency specification (FIX #162, impossible using latest numpy version)

  • made all dependency specifications more permissive following the same rationale

6.1.3 (2022-09-23)

  • bugfix broken package build in the case of a broken cffi installation (GitHub issue #155). Skip build process if cffi fails. For performance reasons using the C extension should remain the default behavior. Hence the cffi dependency should not be optional.

6.1.2 (2022-09-13)

  • bugfix potentially broken pip install due to a mismatch in cffi versions (GitHub issue #151)

6.1.1 (2022-08-18)

internals:

  • minimized and cleaned up installation footprint (addresses GitHub Issue #151):
    • excluded script, changelog etc. files

    • included C extension into the “timezonefinder” package folder

  • added initialisation speed benchmark

6.1.0 (2022-08-15)

  • included point-in-polygon implementation in C

  • included build script to (optionally) build C point-in-polygon extension automatically during installation

  • added cffi as a dependency to build and interact with the C extension

  • improved initialisation speed: read timezone polygon id index (h3 mapping) with np.fromfile

  • improved CLI speed: construct TimezoneFinder() instances only on demand

internals:

  • updated documentation: Numba installation is no longer recommended (it is a huge dependency and should be optional)

  • clarified documentation: TimezoneFinder() instances should be reused

  • added separate speed benchmark scripts for point in polygon algorithm implementations and the different timezone finding functions

  • added separate section in the documentation for performance including speed benchmark results

  • added checks if all timezone polygons are actually in use (appear in index) to the file conversion script

  • added and improved utility functions as well as tests

  • improved typing

6.0.2 (2022-07-08)

  • bump numpy dependency version to 1.22 (vulnerability fix)

  • officially supported python versions >=3.8,<3.11 (due to numpy and numba constraints)

  • packaging now completely based on pyproject.toml (poetry)

6.0.1 (2022-05-20)

  • explicitly included py.typed in the package to allow mypy users to run static type checking

6.0.0 (2022-05-09)

breaking changes:

  • new dependency: using h3 for indexing the timezone polygons to check (“shortcuts) instead of the previous own indexing implementation. technical details: storing all 41,162 hex cells at resolution 3 and the corresponding timezone polygons which appear in them in the shortcuts.bin (~500 KB).

  • removed .closest_timezone_at(): with the current data set with ocean zones in use, any point is included in some zone. it is therefore not meaningful to search for the closest boundary! Also the timezone polygons do NOT follow the shorelines. This makes the results of closest_timezone_at() somewhat less expressive. Maintaining the non-trivial distance computation algorithms is not really at the core responsibility of this package.

  • officially only supporting python>=3.7 (removed official support for python3.6, since the numpy dependency did so)

  • removed v from the github release/version tags

internals:

  • updated the data to 2021c. please note that timezone polygons might be overlapping (cf. e.g. timezone-boundary-builder/issue/105) and that hence a query coordinate can actually match multiple time zones. timezonefinder does currently NOT support such multiplicity and will always only return the first found match.

  • shortcuts: sorting according to size of polygons (amount of coordinates) instead of the count of zone ids. useful as optimisation: smaller polygons will be checked first and can hence be “ruled-out” faster

  • “most common”: now meaning the zone with the largest polygons in the shortcut (last in the shortcut sorting). please note that this does not necessarily mean the most area in the shortcut is covered by this zone. the polygon size is just an easier to compute heuristic.

  • officially supporting python versions >=3.7,<3.11 (like numba)

  • using poetry for dependency management

  • using GitHub actions for CI instead of travis

  • some minor typing improvements

  • pre-commit hook improvements

In case you have criticism or feedback please reach out by creating an issue, discussion or PR on GitHub.

5.2.0 (2021-02-09)

  • added function unique_timezone_at() (based on the request in issue #112). Allows querying for the unique zone within the corresponding shortcut.

5.1.1 (2021-02-03)

  • BUGFIX: get_geometry() now also works for the last zone

  • add get_geometry() tests

  • black code style

  • pre-commit checks

5.1.0 (2021-01-14)

  • update the command line interface. the package can now directly be called with timezonefinder

  • added the new query functions to the command line interface (to match the online API)

5.0.0 (2020-12-23)

MAJOR CHANGES:

Due to multiple user requests the ocean timezones (“Etc/GMT+-XX”) are now included in the data files per default. fix #88. Since ocean timezones span the whole globe, now every point lies within a timezone!

API changes: * added timezone_at_land(): replaces the previous timezone_at() and returns None in case of a matched ocean timezone.

  • deprecated certain_timezone_at(). only meaningful in the case of timezone data WITHOUT oceans. Has equal results as timezone_at(), but is more expensive to use.

  • also looking a single closest timezone boundary with closest_timezone_at() is not really meaningful, since every point lies within a zone!

  • refactored tests. new test cases for ocean timezones

4.5.0 (2020-11-06)

BUGFIX: handle output destination for data files correctly in file_converter.py (FIX #107)

4.4.1 (2020-08-04)

BUGFIX: a longitude of 180 equals -180 (not 0.0 as previously implemented)

4.4.0 (2020-05-14)

  • added new class TimezonefinderL for using JUST shortcuts (without timezone polygon data)

  • therefore included the most common timezone of each shortcut stored in the binary file shortcuts_direct_id.bin

  • introduced typing

  • included API documentation

  • read hole registry directly from json, hole_poly_ids.bin not required any more

  • added the parse_data.sh shell script for downloading the latest timezone data, also with oceans

improvements of file_converter.py:

  • added command line arguments for specifying the input and output directories

  • read binary names from global_settings.py

  • read data types from global_settings.py

  • use with statement for writing binaries

  • automatically detect overflow for each data type in use

  • cleanup code, remove redundancies, improve codestyle

  • fixing #101: make imports work for local and remote execution

4.3.1 (2020-04-29)

  • BUGFIX #99: include the correct timezone_names.json in build

  • wheel specific for the supported python versions (3.6, 3.7, 3.8)

4.3.0 (2020-04-28)

  • updated the data to 2020a

  • added “extra” simplifying the installation of Numba

  • added minimal required python version

  • added minimal required version of the dependencies

  • simplified and updated settings (e.g. reading current version from file)

  • also testing python 3.8 now

  • loading version from file

4.2.0 (2019-12-15)

  • added option to specify the location of the binary data files to use. making it possible to easily point to own compiled data. also load timezone names json from this location

  • make timezone names a class attribute (instead of a global variable)

  • simplify code for opening and closing multiple binary files

  • added tests for a specified path to the data

  • testing multiple python3 versions automatically

  • pinned new requirements

  • importlib_resources removed from the dependencies

  • added a documentation at: https://timezonefinder.readthedocs.io/en/latest/

  • added contribution guidelines

4.1.0 (2019-07-07)

  • updated the data to 2019b

  • added description of using vectorized input in readme

4.0.3 (2019-06-23)

  • clarification of readme: referenced latest timezonefinderL release, better rst headlines, updated shield.io banner syntax

  • clarification of speedup times (exponential notation)

  • removed six and py2 dependency from tests

  • minor updates to publishing routine

  • minor improvement in timezone_at(): conversion coordinates to int later only when required

4.0.2 (2019-04-01)

  • updated the data to 2019a

4.0.1 (2019-03-12)

  • BUGFIX: fixing #77 (missing dependency in setup.py)

4.0.0 (2019-03-12)

  • ATTENTION: Dropped Python2 support (#72)! six dependency no longer required.

  • BUGFIX: fixing #74 (broken py3 with numba support)

  • added in_memory-mode (adapted unit tests to test both modes, added speed tests and explanation to readme)

  • use of timeit in speed tests for more accurate results

  • dropped use of kwargs_only decorator (can be implemented directly with python3)

3.4.2 (2019-01-15)

  • BUGFIX: fixing #70 (broken py2.7 with numba support)

  • added automatic tox tests for py2.7 py3 environments with numba installed

  • fixed coverage report

3.4.1 (2019-01-13)

  • added test cases for the Numba helpers (#55)

  • added more polygon tests to test the function inside_polygon()

  • added global data type definitions (format strings) to global_settings.py

  • removed tzwhere completely from the main tests (no comparison any more).

  • removed code drafts for ahead of time compilation (#40)

3.4.0 (2019-01-06)

  • updated the data to 2018i

  • introduced global_settings.py to globally define settings and get rid of “magic numbers”.

3.3.0 (2018-11-17)

  • updated the data to 2018g

3.2.1 (2018-10-30)

  • ATTENTION: the package importlib_resources is now required

  • fixing automatic Conda build by exchanging pkg_resources.resource_stream with importlib_resources.open_binary

  • added tests for overflow in helpers.py/inside_polygon()

3.2.0 (2018-10-23)

  • ATTENTION: the package kwargs_only is not a requirement any more!

  • fixing #63 (kwargs_only not in conda) enabling automatic conda forge builds by directly providing the kwargs_only functionality again

  • added example.py with the code examples from the readme

  • fixing #62 (overflow happening because of using numpy.int32): forcing int64 type conversion

3.1.0 (2018-09-27)

  • fixing typo in requirements.txt

  • updated publishing routine: reminder to include all direct dependencies and to compile the requirements.txt with python 2 (pip-tools)

3.0.2 (2018-09-26)

  • ATTENTION: the package kwargs_only is now required! This functionality has previously been implemented by the author directly within this package, but some code features got deprecated.

  • updated build/testing/publishing routine

  • fixing issue #61 (six dependency not listed in setup.py)

  • no more default arguments for timezone_at() and certain_timezone_at()

  • no more comparison to (py-)tzwhere in the tests (test_it.py)

  • updated requirements.txt (removed tzwhere and dependencies)

  • prepared helpers_test.py for also testing helpers_numba.py

  • exchanged deprecated inspect.getargspec() into .getfullargspec() in functional.py

3.0.1 (2018-05-30)

  • fixing minor issue #58 (readme not rendering in pyPI)

3.0.0 (2018-05-17)

  • ATTENTION: the package six is now required! (was necessary because of the new testing routine. improves compatibility standards)

  • updated build/testing/publishing routine

  • updated the data to 2018d

  • fixing minor issue #52 (shortcuts being out of bounds for extreme coordinate values)

  • the list of polygon ids in each shortcut is sorted after freq. of appearance of their zone id.

    this is critical for ruling out zones faster (as soon as just polygons of one zone are left this zone can be returned)

  • using argparse package now for parsing the command line arguments

  • added option of choosing between functions timezone_at() and certain_timezone_at() on the command line with flag -f

  • the timezone names are now being stored in a readable JSON file

  • adjusted the main test cases

  • corrections and clarifications in the readme and code comments

2.1.2 (2017-11-20)

  • bugfix: possibly uninitialized variable in closest_timezone_at()

2.1.1 (2017-11-20)

  • updated the data to 2017c

  • minor improvements in code style and readme

  • include publishing routine script

2.1.0 (2017-05-19)

  • updated the data to 2017a (tz_world is not being maintained any more)

  • the file_converter has been updated to parse the new format of .json files

  • the new data is much bigger (based on OSM Data, +40MB). I am sorry for this but its still better than small outdated data!

  • in case size and speed matter more you than actuality, you can still check out older versions of timezonefinder(L)

  • the new timezone polygons are not limited to the coastlines, but they are including some large parts of the sea. This makes the results of closest_timezone_at() somewhat meaningless (as with timezonefinderL).

  • the polygons can not be simplified much more and as a consequence timezonefinderL is not being updated any more.

  • simplification functions (used for compiling the data for timezonefinderL) have been deleted from the file_converter

  • the readme has been updated to inform about this major change

  • some tests have been temporarily disabled (with tzwhere still using a very old version of tz_world, a comparison does not make too much sense atm)

2.0.1 (2017-04-08)

  • added missing package data entries (2.0.0 didn’t include all necessary .bin files)

2.0.0 (2017-04-07)

  • ATTENTION: major change!: there is a second version of timezonefinder now: timezonefinderL. There the data has been simplified

    for increasing speed reducing data size. Around 56% of the coordinates of the timezone polygons have been deleted there. Around 60% of the polygons (mostly small islands) have been included in the simplified polygons. For any coordinate on landmass the results should stay the same, but accuracy at the shorelines is lost. This eradicates the usefulness of closest_timezone_at() and certain_timezone_at() but the main use case for this package (= determining the timezone of a point on landmass) is improved. In this repo timezonefinder will still be maintained with the detailed (unsimplified) data.

  • file_converter.py has been complemented and modified to perform those simplifications

  • introduction of new function get_geometry() for querying timezones for their geometric shape

  • added shortcuts_unique_id.bin for instantly returning an id if the shortcut corresponding to the coords only contains polygons of one zone

  • data is now stored in separate binaries for ease of debugging and readability

  • polygons are stored sorted after their timezone id and size

  • timezonefinder can now be called directly as a script (experimental with reduced functionality, cf. readme)

  • optimisations on point in polygon algorithm

  • small simplifications in the helper functions

  • clarification of the readme

  • clarification of the comments in the code

  • referenced the new conda-feedstock in the readme

  • referenced the new timezonefinder API/GUI

1.5.7 (2016-07-21)

  • ATTENTION: API BREAK: all functions are now keyword-args only (to prevent lng lat mix-up errors)

  • fixed a little bug with too many arguments in a @jit function

  • clarified usage of the package in the readme

  • prepared the usage of the ahead of time compilation functionality of Numba. It is not enabled yet.

  • sorting the order of polygons to check in the order of how often their zones appear, gives a speed bonus (for closest_timezone_at)

1.5.6 (2016-06-16)

  • using little endian encoding now

  • introduced test for checking the proper functionality of the helper functions

  • wrote tests for proximity algorithms

  • improved proximity algorithms: introduced exact_computation, return_distances and force_evaluation functionality (s. Readme or documentation for more info)

1.5.5 (2016-06-03)

  • using the newest version (2016d, May 2016) of the tz world data

  • holes in the polygons which are stored in the tz_world data are now correctly stored and handled

  • rewrote the file_converter for storing the holes at the end of the timezone_data.bin

  • added specific test cases for hole handling

  • made some optimizations in the algorithms

1.5.4 (2016-04-26)

  • using the newest version (2016b) of the tz world data

  • rewrote the file_converter for parsing a .json created from the tz_worlds .shp

  • had to temporarily fix one polygon manually which had the invalid TZID: ‘America/Monterey’ (should be ‘America/Monterrey’)

  • had to make tests less strict because tzwhere still used the old data at the time and some results were simply different now

1.5.3 (2016-04-23)

  • using 32-bit ints for storing the polygons now (instead of 64-bit): I calculated that the minimum accuracy (at the equator) is 1cm with the encoding being used. Tests passed.

  • Benefits: 18MB file instead of 35MB, another 10-30% speed boost (depending on your hardware)

1.5.2 (2016-04-20)

  • added python 2.7.6 support: replaced strings in unpack (unsupported by python 2.7.6 or earlier) with byte strings

  • timezone names are now loaded from a separate file for better modularity

1.5.1 (2016-04-18)

  • added python 2.7.8+ support:

    Therefore I had to change the tests a little bit (some operations were not supported). This only affects output. I also had to replace one part of the algorithms to prevent overflow in Python 2.7

1.5.0 (2016-04-12)

  • automatically using optimized algorithms now (when numba is installed)

  • added TimezoneFinder.using_numba() function to check if the import worked

1.4.0 (2016-04-07)

  • Added the file_converter.py to the repository: It converts the .csv from pytzwhere to another .csv and this one into the used .bin.

    Especially the shortcut computation and the boundary storage in there save a lot of reading and computation time, when deciding which timezone the coordinates are in. It will help to keep the package up to date, even when the timezone data should change in the future.