dtrexp 1.0.0

Date-Time Range & Recurrence Expression — a compact coverage-expression language (DTRExp draft 2.8)
Documentation
  • Coverage
  • 88.24%
    15 out of 17 items documented1 out of 7 items with examples
  • Size
  • Source code size: 182.58 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 897.43 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 2s Average build duration of successful builds.
  • all releases: 2s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • DTRExp/dtrexp-rs
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • onury

dtrexp-rs

Rust implementation of DTRExp (read: "DTR Expression") — a compact string expression for date-time ranges and recurrence, evaluated by coverage rather than enumeration.

T0900:1800 E1:5          Mon–Fri, 09:00–18:00
E7#-1 M4                 last Sunday of April, every year
20200106/10D             every 10 days from 2020-01-06 (cron can't say this)
M!7                      every month except July

Scope: parsing, validation and coverage evaluation (the spec's core interface). Rendering, description and RRULE export are out of scope; the reference implementation has them.

Install

cargo add dtrexp

Rust 2021 edition. No dependencies, including the zone handling; IANA zones are read straight from the system TZif database.

Usage

use dtrexp::{parse, Tz};

let dtr = parse("T0900:1800 E1:5").unwrap();   // business hours, Mon–Fri

// 2026-07-07 (a Tuesday) 10:00:00Z, in ms since the Unix epoch:
let t: i64 = 1_783_418_400_000;

let ok = dtr.covers(t, "Europe/Berlin").unwrap();
// —> true; a weekday, 09:00–18:00 Berlin local time.
// The zone is an evaluation parameter, never part of the expression;
// an empty identifier or "UTC" means UTC.

// Preloaded zone; cannot fail:
let berlin = Tz::load("Europe/Berlin").unwrap();
let ok = dtr.covers_in(t, &berlin);

Instants are milliseconds since the Unix epoch (UTC); the time zone is passed at evaluation, and the default is Tz::utc(). Note that you parse once (at write/config time) and evaluate many; a Dtrexp value is immutable after parse. covers is a single calendar-field extraction followed by integer comparisons; no occurrence iteration.

Errors and Warnings

Both a ParseError and a Warning carry a position; the byte offset into the source where the problem was detected.

let err = dtrexp::parse("T2500").unwrap_err();      // hour out of range
err.pos;        // 1 — points at the offending token
err.message;    // "hour out of range — 24 exists only as the exact token '2400'"

let warnings = dtrexp::validate("D30 M2").unwrap();  // parses cleanly
warnings[0].pos;      // 0
warnings[0].message;  // "unsatisfiable — day never exists …"  (no February has 30 days)
  • parse(s) returns the expression or a ParseError { pos, message }. Warnings from a clean parse are available via Dtrexp::warnings().
  • validate(s) returns Result<Vec<Warning>, ParseError>: the warnings on success, or the same ParseError when the input does not parse. It carries the same warnings as Dtrexp::warnings().
  • covers / covers_in take an IANA zone. An identifier that does not resolve is the one runtime failure, UnknownTimeZone { id, message }; covers_in takes an already-loaded Tz and cannot fail.
  • Warnings are the spec's §9.1 unsatisfiability lint: expressions that parse but can never match.

Conformance & Quality

  • The test suite is driven by the shared vectors.json from the spec repo (draft 2.8), vendored at tests/vectors.json: every coverage, rejection, warning and quiet vector, including the calendar traps (Feb 29 across 2000/2024/2100, W53 existence, DST gap/overlap in Europe/Berlin). Run cargo test. See VECTORS.md for how the suite works.
  • Hand-rolled TZif reader. Tz::load reads the system zoneinfo database directly; there is no time-zone crate underneath.
  • Zero dependencies.

Related Projects

  • dtrexp (spec) — the DTRExp specification (grammar, semantics, conformance vectors) this package implements.
  • dtrexp-js — the reference implementation; adds intersect, next, describe, toRRule and canonicalization.
  • dtrexp-py · dtrexp-go · dtrexp-swift · dtrexp-java — the other ports; same core interface.
  • dtrexp-wasm — this crate compiled to WebAssembly for JS hosts.

License

© 2026, Onur Yıldırım. MIT License.