cronspeak 0.1.1

Convert cron expressions into clear, human-readable English descriptions (like cronstrue / cron-descriptor). Zero-dependency, no_std.
Documentation
# cronspeak

[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-)

[![Crates.io](https://img.shields.io/crates/v/cronspeak.svg)](https://crates.io/crates/cronspeak)
[![Documentation](https://docs.rs/cronspeak/badge.svg)](https://docs.rs/cronspeak)
[![CI](https://github.com/trananhtung/cronspeak/actions/workflows/ci.yml/badge.svg)](https://github.com/trananhtung/cronspeak/actions/workflows/ci.yml)
[![License](https://img.shields.io/crates/l/cronspeak.svg)](#license)
[![no_std](https://img.shields.io/badge/no__std-yes-brightgreen.svg)](#no_std)

**Say cron out loud.** Turn cron expressions into clear, human-readable English —
the way [`cronstrue`](https://github.com/bradymholt/cRonstrue) (JavaScript) and
[`cron-descriptor`](https://pypi.org/project/cron-descriptor/) (Python) do.

```rust
assert_eq!(cronspeak::describe("0 9 * * 1-5").unwrap(), "At 09:00 AM, Monday through Friday");
assert_eq!(cronspeak::describe("*/15 * * * *").unwrap(), "Every 15 minutes");
assert_eq!(cronspeak::describe("0 0 1 * *").unwrap(),  "At 12:00 AM, on day 1 of the month");
assert_eq!(cronspeak::describe("@daily").unwrap(),     "At 12:00 AM");
```

Zero dependencies. `#![no_std]` (needs only `alloc`). Pure logic — easy to trust.

## Why cronspeak?

Rust has excellent crates for *running* cron schedules
([`cron`](https://crates.io/crates/cron), [`croner`](https://crates.io/crates/croner)),
but nothing maintained for **explaining** one to a human. cronspeak fills that
gap — perfect for admin dashboards, scheduling UIs, config validators, and CLIs
that want to show *"this job runs: …"*.

## Install

```toml
[dependencies]
cronspeak = "0.1"
```

## Usage

```rust
use cronspeak::{describe, describe_with, Options, TimeFormat};

// Default: 12-hour clock.
assert_eq!(describe("30 14 * * *").unwrap(), "At 02:30 PM");

// 24-hour clock.
let opts = Options::new().time_format(TimeFormat::H24);
assert_eq!(describe_with("0 9 * * 1-5", &opts).unwrap(), "At 09:00, Monday through Friday");
```

### More examples

| Expression | Description |
| --- | --- |
| `* * * * *` | Every minute |
| `*/5 * * * *` | Every 5 minutes |
| `0 * * * *` | At 0 minutes past the hour |
| `0 0 * * *` | At 12:00 AM |
| `0 9 * * 1-5` | At 09:00 AM, Monday through Friday |
| `0 0,12 * * *` | At 12:00 AM and 12:00 PM |
| `0 0 1,15 * *` | At 12:00 AM, on days 1 and 15 of the month |
| `*/15 9-17 * * 1-5` | Every 15 minutes, between 09:00 AM and 05:59 PM, Monday through Friday |
| `0 0 1 1 *` | At 12:00 AM, on day 1 of the month, only in January |
| `@yearly` | At 12:00 AM, on day 1 of the month, only in January |

## Supported syntax

Standard **5-field** cron (`minute hour day-of-month month day-of-week`) with:

- `*` (every), single values, lists (`a,b,c`), ranges (`a-b`), steps (`*/n`, `a-b/n`, `a/n`)
- month names `JAN``DEC` and weekday names `SUN``SAT` (case-insensitive)
- both `0` and `7` for Sunday
- macros: `@yearly`/`@annually`, `@monthly`, `@weekly`, `@daily`/`@midnight`, `@hourly`

Out-of-range values, inverted ranges, zero steps, and wrong field counts return a
typed [`CronError`]. Non-standard `L`/`W`/`#` qualifiers and 6/7-field (seconds /
year) expressions are not supported in this release.

## no_std

`cronspeak` is `#![no_std]` and only needs `alloc`. It builds for bare-metal
targets such as `thumbv7em-none-eabi`.

## Contributors ✨

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome — code, docs, bug reports, ideas, reviews! See the [emoji key](https://allcontributors.org/docs/en/emoji-key) for how each contribution is recognized, and open a PR or issue to get involved.

Thanks goes to these wonderful people:

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
  <tbody>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/trananhtung"><img src="https://avatars.githubusercontent.com/u/30992229?v=4?s=100" width="100px;" alt="Tung Tran"/><br /><sub><b>Tung Tran</b></sub></a><br /><a href="https://github.com/trananhtung/cronspeak/commits?author=trananhtung" title="Code">💻</a> <a href="#maintenance-trananhtung" title="Maintenance">🚧</a></td>
    </tr>
  </tbody>
</table>

<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

## License

Licensed under either of [Apache-2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT) at
your option.