Releases: simpllyf/hron
Release list
v2.0.0
hron 2.0.0
hron 2.0 makes every implementation keep one exact contract. The same expression gives the same occurrences, the same cron conversion, the same error message and span, and the same public API in Rust, TypeScript, WebAssembly, Python, Go, Java, C#, Ruby and Dart. Shared spec files define that contract, and every package's tests run against them (#84, #95, #96, #98, #99, #101). This release also adds a ninth implementation, a native Swift package (#102).
It is a major version because getting there changes public APIs in every package. Some names are renamed, internals are no longer exported, and schedules can no longer be changed after they are built. Wrong-type and null arguments now raise each platform's own usage error. Some inputs that used to parse are now rejected, and every error message has new text. Each break is listed below by package.
Highlights
- One contract, checked everywhere.
spec/tests.jsongained hundreds of fixed-answer cases and a set of invariants (#84).spec/build.jsoncovers schedules built in code (#99), andspec/api.jsoncovers the public API of every language (#101). Each runner fails on any case it cannot check (#84). - Correct evaluation in every language. The implementations used to disagree on more than a thousand generated cases, and in 735 more they agreed on a wrong answer. These are fixed, and DST handling is now the same in every zone (#84). Searches find occurrences that lie past one-off
exceptdates (#88). - Invalid schedules fail at parse time. Once a schedule parses, evaluating it cannot fail (#85).
- Exact cron conversion.
fromCronandtoCrongive a schedule that fires at the same local times on the same dates, or they fail with a clear message (#95). - One error per mistake. Every lex and parse error has the same kind, message, span and suggestion in every language, and spans count Unicode code points (#96).
- Timestamps are instants. Timestamp arguments are read as instants, and results come back in the schedule's zone, or in UTC when the schedule has none (#98).
- Immutable schedules with getters and equality. A schedule cannot change after it is built. It has six read-only getters, and two schedules are equal when their parts are equal (#99, #101).
- Faster. All nine evaluators share one search design. In a stress set of DST cases, total evaluation time fell in every language, for example Go from 30s to 14s and Java from 4.9s to 2.5s (#89, #90, #91, #92).
- New: Swift. A native Swift package with no dependencies, installed with SwiftPM (#102).
- New home. The repository is now
github.com/simpllyf/hron, and the Go module path is nowgithub.com/simpllyf/hron/go/v2(#94).
Breaking changes by package
Changes that apply to every package are described under Behaviour changes: stricter parsing (#85, #96), new error message text (#95, #96), and some fromCron results written in a different form (#95).
Rust: hron (crates.io)
Schedule::from_parts(ScheduleParts) -> Resultandto_parts()replaceSchedule::newand thewith_timezone,with_except,with_until,with_anchorandwith_duringmethods. Parts are checked with the same rules asparse, and a bad part fails with anevalerror (#99).- Evaluation can no longer fail, so
next_from,previous_from,next_n_fromandmatchesreturn their values directly instead of aResult, and theoccurrencesandbetweeniterators yieldZoned(#99). Schedule::expr()is renamed toexpression(), andanchor()is renamed tostarting()(#101).- Error spans count Unicode code points, not bytes.
Spankeeps its type, so code that slices the input with a span must convert it. The README shows how (#96).
Also new: Hash is implemented on Schedule and on every part type. ErrorKind is new, and ScheduleError gains the accessors kind(), message(), span(), input() and suggestion(). ErrorKind and Span are re-exported at the crate root (#101).
CLI: hron-cli (crates.io and release binaries)
--nis replaced by-n/--count(#101).--fromwithout-nprints one occurrence, not up to 100 (#101).- A usage error exits with status 2 (#98).
-ntogether with--tois now a usage error. So is--explainor--from-crontogether with an expression, or the two together (#101).
Also changed: --from and --to take the same RFC 9557 or RFC 3339 strings as WebAssembly, with an offset or Z, and negative years are accepted (#98). --json prints [] when nothing is found (#101). Without --to, an empty result now prints the note "no occurrences after --from" (#101). Piping the output to head no longer panics (#98).
WebAssembly: hron-wasm (npm)
- A timestamp string without an offset is rejected. Strings may be RFC 9557 or RFC 3339, with an offset or
Z, includingDate.prototype.toISOString()output (#98). - An argument of the wrong type throws
TypeError, and a bad value throwsRangeError. Both used to trap withRuntimeError: memory access out of bounds(#98). - An
norlimitof 0 or less returns[], where -1 used to wrap to 4294967295. A non-integer such as1.5throws (#98). toJSON()returns a plain object, where it used to return aMapthat serialized as{}. Absent fields arenull(#98).timezone,nextFromandpreviousFromreturnnullinstead ofundefined(#101).- A non-string input to
parse,validate,fromCronorexplainCronthrowsTypeError. A number used to trap (#101).
Also new: explainCron is exported, as its README already showed (#95). Errors carry kind (#95), plus span, suggestion, input and displayRich() (#96). New getters return the same plain objects as hron-ts, frozen at every level, and there is a new equals(other). The .d.ts now types the part types, HronError, HronErrorKind and Span (#101). Array returns are typed string[] (#98).
TypeScript: hron-ts (npm)
- Timestamp arguments are checked when the method is called.
Temporal.ZonedDateTimeandTemporal.Instantare accepted, native or polyfilled, and anything else is aTypeError(#98). - A non-integer
nis aRangeError.nextNFrom(now, 1.5)used to run to the end of the supported range (#98). occurrencesandbetweenreject bad arguments when they are called, not on the firstnext()(#98).expressionis deeply frozen, and the AST types arereadonly(#99).new Schedule(...)called from JavaScript throws. Build schedules withparseorfromCron(#99).- A non-string input to
parse,validateorfromCronthrowsTypeError, andvalidateno longer returnsfalsefor one (#101). validateno longer swallows errors that are not aHronError(#101).- The
HronErrorconstructors throwTypeErrorfor a bad message, input, suggestion or span (#101). - The
ScheduleDatatype export is removed (#101). - Error spans count Unicode code points, not UTF-16 code units. The numbers change only for input that contains characters outside the Basic Multilingual Plane (#96).
Also new: the getters except, until, starting and during, which return frozen values, and equals(other). NearestDirection is now exported (#101).
Python: hron (PyPI)
ScheduleData(expr=..., anchor=...)is nowScheduleData(expression=..., starting=...)(#101).HronError.input_textis nowHronError.input(#101).- A non-
strinput toparse,validateorfrom_cronraisesTypeError(#101). HronError(...)and its constructors raiseTypeErrorfor an argument of the wrong type (#101).ScheduleDatais frozen, and its lists are tuples (#99).Schedule(ScheduleData(...))checks its parts with the same rules asparse, and a value of the wrong type is aTypeError(#99).- The internal
to_cron,display,parseand the like can no longer be imported fromhron(#99). - A timestamp argument that is not a
datetimeraisesTypeError, notAttributeError(#98). nis converted withoperator.index, so a non-integernraisesTypeError(#98).
Also new: the properties except_, until, starting and during, and HronError.message (#101). Schedule has value equality and a data property, and NearestWeekdayTarget and NearestDirection are exported (#99). OrdinalPosition.LAST.to_n() returns -1, where it used to raise KeyError (#99).
Go: github.com/simpllyf/hron/go/v2
- The module path is now
github.com/simpllyf/hron/go/v2. Released v1 versions stay available under their old path (#94). Parse,Display,FromCron,ToCronandTokenize, which took or returned rawScheduleData, are no longer exported. UseParseSchedule,String(),FromCronExprandSchedule.ToCron(#99).NewSchedulechecks every part with the same rules as parsing and copies it deeply. A bad part fails with anevalerror, and a bad timezone, which used to be aparseerror, is one of them (#99).Data()returns a copy (#99).ScheduleData.Expris nowExpression, andAnchoris nowStarting(#101).Token,TokenKindand theToken*constants are no longer exported (#101).- The package-level
OccurrencesandBetweenfunctions are no longer exported. The methods remain (#101). HronError.Spancounts Unicode code points, not bytes. It keeps its type, so code that slices the input with it must convert. The README shows how (#96).
Also new: the getter methods Expression(), Except(), Until(), Starting() and During(), which return copies, and Equal(other) (#101).
Java: io.hron:hron (Maven Central)
v1.0.0
What's Changed
- chore: bump hron wasm for playground by @prasrvenkat in #70
- chore: harden Rust API surface and expand conformance suite for 1.0 by @prasrvenkat in #71
- chore: harden API surface and version-stamp spec files for 1.0 by @prasrvenkat in #72
- chore: pre-1.0 hardening — spec docs, every week syntax, API tightening by @prasrvenkat in #73
- release: v1.0.0 by @prasrvenkat in #74
Full Changelog: v0.6.1...v1.0.0
v0.6.1
What's Changed
- feat: implement comprehensive from_cron support with full cron parity by @prasrvenkat in #54
- feat: implement nearest weekday (W) support across all languages by @prasrvenkat in #55
- feat: implement occurrences and between iterator API by @prasrvenkat in #56
- feat: implement previousFrom() across all language bindings by @prasrvenkat in #57
- chore: audit fixes, dynamic section discovery, and documentation by @prasrvenkat in #58
- test: expand conformance suite with datetime edge case tests by @prasrvenkat in #59
- fix: validate ISO dates semantically at parse time by @prasrvenkat in #60
- fix: eliminate silent timezone error swallowing in Go eval by @prasrvenkat in #61
- chore: add setup/format/lint just recipes and use them in CI by @prasrvenkat in #62
- refactor!: fold OrdinalRepeat into MonthRepeat by @prasrvenkat in #63
- fix: add explicit errors for unhandled variants in display modules by @prasrvenkat in #64
- fix: validate parser inputs and improve eval safety across all implementations by @prasrvenkat in #65
- release: v0.6.0 by @prasrvenkat in #66
- fix: escape HTML entities in Javadoc comment by @prasrvenkat in #67
- fix: fix javadoc warnings and remove unnecessary --enable-preview by @prasrvenkat in #68
- release: v0.6.1 by @prasrvenkat in #69
Full Changelog: v0.6.0...v0.6.1
v0.5.1
What's Changed
- ci: add Go subdirectory tag to tag workflow by @prasrvenkat in #41
- feat(java): add native Java 25 implementation by @prasrvenkat in #42
- chore: fix Java metadata and add secrets to gitignore by @prasrvenkat in #43
- feat(playground): add landing page for hron.io by @prasrvenkat in #44
- feat(csharp): add native C# implementation by @prasrvenkat in #45
- test(java): add spec coverage validation to API conformance tests by @prasrvenkat in #46
- chore: audit fixes for code quality and CI improvements by @prasrvenkat in #47
- chore(dart): upgrade to Dart 3.11 and improve pub.dev score by @prasrvenkat in #48
- feat(ruby): add native Ruby implementation by @prasrvenkat in #49
- fix: default to UTC when no timezone specified by @prasrvenkat in #50
- release: v0.5.0 by @prasrvenkat in #51
- fix: correct release workflow action versions by @prasrvenkat in #52
- release: v0.5.1 by @prasrvenkat in #53
Full Changelog: v0.4.2...v0.5.1
v0.4.2
What's Changed
- feat: add native Python implementation by @prasrvenkat in #30
- ci: remove .tool-versions from rust.yml path filter by @prasrvenkat in #31
- test(python): add API conformance tests against spec/api.json by @prasrvenkat in #32
- feat: add interactive hron playground by @prasrvenkat in #33
- fix(playground): regenerate lockfile for latest specifier by @prasrvenkat in #34
- ci: add build check for playground on PRs by @prasrvenkat in #35
- docs(rust): add doc examples, runnable examples, and README fixes by @prasrvenkat in #36
- feat(go): add native Go implementation by @prasrvenkat in #37
- ci(go): add Go module tagging and proxy indexing to release by @prasrvenkat in #38
- ci(go): add format check and split into check/test jobs by @prasrvenkat in #39
- release: v0.4.2 by @prasrvenkat in #40
Full Changelog: v0.4.1...v0.4.2
v0.4.1
What's Changed
- fix: make hron-wasm compatible with Cloudflare Workers by @prasrvenkat in #28
- release: v0.4.1 by @prasrvenkat in #29
Full Changelog: v0.4.0...v0.4.1
v0.4.0
What's Changed
** BREAKING CHANGES **
- docs: add registry version badges to packages table by @prasrvenkat in #24
- Add pre-1.0 stability warning to README by @prasrvenkat in #25
- feat!: audit improvements — error surfacing, DST fix, benchmarks & fuzz by @prasrvenkat in #26
- release: v0.4.0 by @prasrvenkat in #27
Full Changelog: v0.3.2...v0.4.0
v0.3.2
What's Changed
** BREAKING CHANGES **
- feat: add interval support for day/month/ordinal/year repeats by @prasrvenkat in #16
- feat!: cross-language API conformance & WASM tests by @prasrvenkat in #18
- fix(ci): make release workflow publish reliably by @prasrvenkat in #20
- fix(ci): remove setup-node to fix npm OIDC trusted publishing by @prasrvenkat in #22
Full Changelog: v0.1.2...v0.3.2
v0.1.2
What's Changed
- fix(ci): make release workflow idempotent and fix macOS build by @prasrvenkat in #11
- refactor(ci): split release into tag + release workflows by @prasrvenkat in #13
- release: v0.1.2 by @prasrvenkat in #14
- fix(ci): make release workflow manual dispatch on tag ref by @prasrvenkat in #15
Full Changelog: v0.1.1...v0.1.2
v0.1.1
What's Changed
- chore: first release fixups (hron-js → hron-ts, pub.dev OIDC) by @prasrvenkat in #6
- chore: switch npm publishing to OIDC trusted publishing by @prasrvenkat in #7
- release: v0.1.1 by @prasrvenkat in #8
- fix(ci): add workflow-level permissions for release by @prasrvenkat in #9
- fix(ci): add workflow_dispatch to release workflow by @prasrvenkat in #10
Full Changelog: v0.1.0...v0.1.1