python-date-parser
Perform fast fuzzy parsing of dates in varying formats.
Status
The Rust extension exposes three parsing functions:
-
parse(raw: str) -> str | None— accepts a single raw date string and returns its ISO-8601 representation (orNonefor inputs the parser can't handle). No JSON encoding round-trip. -
parse_list(raw_dates: list[str]) -> list[str | None]— accepts a list of raw date strings and returns a list of ISO-8601 strings (orNonefor inputs the parser can't handle). The returned list matches the input length and order. This is the bulk-list path: one Rust call for the whole list, no JSON encoding involved. -
parse_series(s: pl.Series) -> pl.Series— accepts a Polars Series of string dtype and returns a Polars Series ofpl.Datetime("ns")(naive UTC, nanosecond precision). Unparseable strings become null values in the result. The Polars path works directly on the underlying Arrow buffer viapyo3-polars, so there is no Python-level iteration or list materialization.
All three paths use the same parsing logic via the
dateparser crate.
>>> import date_parser
>>> date_parser.parse("2026-01-01")
'2026-01-01 00:00:00+00:00'
>>> date_parser.parse("garbage") is None
True
>>> date_parser.parse_list(["2026-01-01", "garbage", "06/15/2024"])
['2026-01-01 00:00:00+00:00', None, '2024-06-15 00:00:00+00:00']
>>> import polars as pl
>>> date_parser.parse_series(pl.Series(["2026-01-01", "garbage"])).dtype
Datetime('ns')
Note: parsed datetimes are normalized to UTC (+00:00), matching the
behavior of the dateparser Rust crate. The Python dateparser library
preserves the original timezone offset; we don't (yet).
Pure-numeric inputs (e.g. "1511648546") are interpreted as Unix
timestamps and forced to UTC: 10 digits = seconds, 13 = milliseconds,
16 = microseconds, 19 = nanoseconds. The Python dateparser library
interprets these in the local timezone instead.
Installation
pip install gnosis-date-parser
Benchmarking
bin/benchmark.py measures throughput of the three date_parser
entry points side-by-side against the Python
dateparser reference:
# Benchmark all four libraries (the Rust extension has three modes)
uv run python bin/benchmark.py
# Benchmark a single library
uv run python bin/benchmark.py --library date_parser
uv run python bin/benchmark.py --library date_parser_list
uv run python bin/benchmark.py --library date_parser_series
uv run python bin/benchmark.py --library dateparser
# 10 timed iterations instead of the default 5
uv run python bin/benchmark.py -n 10
The --library choices map to the underlying APIs as follows:
--library |
API exercised | Calls per iteration |
|---|---|---|
date_parser |
date_parser.parse(s) (per input) |
len(raw_inputs) |
date_parser_list |
date_parser.parse_list(list) (bulk) |
1 |
date_parser_series |
date_parser.parse_series(s) (Polars/Arrow) |
1 |
dateparser |
dateparser.parse(s) (per input, Python) |
len(raw_inputs) |
After each timed run the script verifies the parsed output against the
expected ISO-8601 values in tests/data/examples.txt and prints any
mismatches.
Local development
The project uses uv for environment and dependency management.
# Create a venv and install dev dependencies (maturin, pytest, ruff,
# mypy, mkdocs-material, ipython).
uv sync --extra dev
# Compile the Rust extension and install it editable into the venv.
uv run maturin develop --release
# Run the smoke tests (parse, parse_list, parse_series).
uv run pytest -q
# Lint and typecheck.
uv run ruff check .
uv run mypy bin tests date_parser
Releasing
Releases are cut by pushing a v* tag; .github/workflows/release.yml
builds wheels for Linux (glibc + musl, x86_64 + aarch64), macOS
(x86_64 + arm64), and Windows (x86_64 + arm64), plus an sdist, and
uploads them to PyPI via Trusted Publishing
(OIDC). No PyPI token is stored in the repository.
# Pick up the current version from pyproject.toml (e.g. 0.1.0).
# Tag and push to trigger the release workflow.
git tag v0.1.0
git push origin v0.1.0
One-time setup on PyPI (at https://pypi.org/manage/account/publishing/):
- Add a pending trusted publisher for
SEIU-Tech/python-date-parser. - Set the workflow filename to
release.ymland leave the environment name blank (or define areleaseGitHub environment and reference it fromrelease.ymlif you want manual approval gating). - Claim ownership of the
gnosis-date-parserproject name on PyPI (or create it if this is the first release).
License
BSD-2-Clause. See LICENSE.
Release files for gnosis-date-parser 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gnosis_date_parser-0.1.0.tar.gz | 133.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gnosis_date_parser-0.1.0-cp310-abi3-manylinux_2_34_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.34+ x86-64 | Details |
Total release size: 4.7 MB
Release files / gnosis_date_parser-0.1.0.tar.gz
| Download URL | gnosis_date_parser-0.1.0.tar.gz |
|---|---|
| Size | 133.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d1ef5ec0bde82e03fd8a85e378259459122f0a6de628ffe91b50404c8aa777e7
|
|
BLAKE2b-256 checksum How to use checksums |
33a6f41d6363ed8dfb3a7e510698b862c60489a64bcd1beb87e468abc9ea3d6d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.0
|
Release files / gnosis_date_parser-0.1.0-cp310-abi3-manylinux_2_34_x86_64.whl
| Download URL | gnosis_date_parser-0.1.0-cp310-abi3-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 4.6 MB |
| Tags | CPython 3.10 Linux glibc 2.34+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
0cf4e07d077b7e0695c92e2962c6a5152307c9c319d2391092b66f4c0addafe8
|
|
BLAKE2b-256 checksum How to use checksums |
dc274534d1156b1cbb876434084fc4c02be12a7c715ab30b136a97c8aca1d163
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.0
|