Human-readable cron — scheduling expressions that are a superset of what cron can express.
every weekday at 9:00 except dec 25, jan 1 until 2027-12-31 in America/New_York
hron is a language specification with native implementations for multiple programming languages. It handles everything cron can do and more: multi-week intervals, ordinal weekdays, yearly schedules, exception dates, end dates, and IANA timezone support with full DST awareness.
hron.io — interactive playground, no install needed.
cargo install hron-cli$ hron "every weekday at 9:00 in America/New_York"
2026-02-09T09:00:00-05:00[America/New_York]
$ hron "every weekday at 9:00" -n 3
2026-02-09T09:00:00+00:00[UTC]
2026-02-10T09:00:00+00:00[UTC]
2026-02-11T09:00:00+00:00[UTC]
$ hron "every day at 9:00" --to-cron
0 9 * * *
$ hron --from-cron "*/30 * * * *"
every 30 min from 00:00 to 23:59
$ hron --explain "0 9 * * 1-5"
every weekday at 09:00See hron-cli for all options.
| Language | Package | Registry |
|---|---|---|
| Rust | hron |
|
| JS/TS (native) | hron-ts |
|
| JS/TS (WASM) | hron-wasm |
|
| Dart/Flutter | hron |
|
| Python | hron |
|
| Go | hron |
|
| Java | hron |
|
| C# | Hron |
|
| Ruby | hron |
Note: The JS/TS native package (
hron-ts) uses the Temporal API via polyfill. Once Temporal ships natively in runtimes, performance improves automatically. For performance-critical JS/TS use cases, consider the WASM package (hron-wasm).
hron is available as a library in multiple languages:
# Rust
cargo add hron
# TypeScript / JavaScript
npm install hron-ts # native
npm install hron-wasm # WASM
# Dart / Flutter
dart pub add hron
# Python
pip install hron
# Go
go get github.com/prasrvenkat/hron/go
# Java (Maven) — add io.hron:hron to pom.xml (see badge above for latest version)
# C# / .NET
dotnet add package Hron
# Ruby
gem install hronSee language-specific READMEs for API docs and examples: Rust · TypeScript · Dart · Python · Go · Java · C# · Ruby · WASM
every day at 09:00
every weekday at 9:00
every weekend at 10:00
every monday at 9:00
every mon, wed, fri at 9:00
every 30 min from 09:00 to 17:00
every 2 hours from 00:00 to 23:59
every 45 min from 09:00 to 17:00 on weekdays
every 2 weeks on monday at 9:00
every 3 weeks on mon, wed at 10:00
every month on the 1st at 9:00
every month on the 1st, 15th at 9:00
every month on the last day at 17:00
every month on the last weekday at 15:00
every month on the first monday at 10:00
every month on the last friday at 16:00
every month on the third thursday at 11:00
every month on the nearest weekday to 15th at 9:00
every month on the next nearest weekday to 1st at 9:00
every month on the previous nearest weekday to 31st at 17:00
every year on dec 25 at 00:00
every year on jul 4 at 12:00
every year on the first monday of march at 10:00
every year on the third thursday of november at 12:00
every year on the 15th of march at 09:00
every year on the last weekday of december at 17:00
every year on the last friday of december at 17:00
on feb 14 at 9:00
on 2026-03-15 at 14:30
Trailing clauses can be combined in this order: except, until, starting, during, in.
every weekday at 9:00 except dec 25, jan 1
every weekday at 9:00 except 2026-07-04
every day at 09:00 until 2026-12-31
every day at 09:00 until dec 31
every 2 weeks on monday at 9:00 starting 2026-01-05
every weekday at 9:00 in America/New_York
every day at 9:00 during jan, jun
every weekday at 9:00 except dec 25 until 2027-12-31 during jan, dec in UTC
except— skip specific dates. Named dates (dec 25) recur every year. ISO dates (2026-07-04) are one-off.until— stop producing occurrences after this date.starting— anchor date for multi-week intervals.during— only fire during specific months.in— IANA timezone. Must be last.
hron can convert to and from standard 5-field cron expressions for the expressible subset:
| hron | cron |
|---|---|
every day at 9:00 |
0 9 * * * |
every weekday at 9:00 |
0 9 * * 1-5 |
every weekend at 10:00 |
0 10 * * 0,6 |
every mon, wed, fri at 9:00 |
0 9 * * 1,3,5 |
every 30 min from 00:00 to 23:59 |
*/30 * * * * |
every 2 hours from 00:00 to 23:59 |
0 */2 * * * |
every month on the 1st at 9:00 |
0 9 1 * * |
Expressions that go beyond cron's capabilities (multi-week intervals, ordinals, yearly, except, until, partial-day windows) will return an error from to_cron().
When a schedule specifies a timezone via the in clause, all occurrences are computed in that timezone with full DST awareness:
- Spring-forward (gap): If a scheduled time doesn't exist (e.g.
2:30 AMduring a spring-forward transition), the occurrence shifts to the next valid time after the gap (typically3:00 AMor later, depending on the gap size). - Fall-back (ambiguity): If a scheduled time is ambiguous (e.g.
1:30 AMoccurs twice during fall-back), the first (pre-transition) occurrence is used. - No timezone: When no
inclause is specified, UTC is used for deterministic, portable behavior.
All implementations (Rust, TypeScript, Dart, Python, Go, Java, C#, Ruby, WASM) follow these same DST semantics.
The conformance test suite includes explicit spring-forward and fall-back test cases to verify this behavior across all implementations.
The spec/ directory contains the language-agnostic conformance test suite (tests.json) and formal grammar (grammar.ebnf). The grammar is a reference specification — all parsers are hand-written recursive descent, not generated from the EBNF. All language implementations must pass the conformance tests.
Requires just.
just test-all # Run tests across all languages
just test-rust # Run Rust tests only
just test-ts # Run TypeScript tests only
just test-dart # Run Dart tests only
just test-python # Run Python tests only
just test-go # Run Go tests only
just test-java # Run Java tests only
just test-csharp # Run C# tests only
just test-ruby # Run Ruby tests only
just build-wasm # Build WASM package
just bench # Run Criterion benchmarks (Rust)
just fuzz # Run fuzz targets (requires nightly, default 3 min)
just stamp-versions # Stamp VERSION into all package manifestsMIT