# `Tempus.Crontab`
[🔗](https://github.com/am-kantox/tempus/blob/v1.0.0-rc.0/lib/crontab.ex#L1)

Helper functions to work with `cron` syntax.

# `t`

```elixir
@type t() :: %Tempus.Crontab{
  day: term(),
  day_of_week: term(),
  hour: term(),
  minute: term(),
  month: term()
}
```

Internal representation of the record in cron file

# `formula`

```elixir
@spec formula(ct :: binary() | t()) :: Formulae.t() | binary() | {:error, any()}
```

Produces the single formula out of cron record. Might be useful
for some external check that requires the single validation call.

_Examples_

    iex> Tempus.Crontab.formula("42 3 28 08 *").formula |> String.split(" && ") |> Enum.sort()
    ["(day == 28)", "(hour == 3)", "(minute == 42)", "(month == 8)", "(rem(day_of_week, 1) == 0)"]

    iex> Tempus.Crontab.formula("423 * * * *")
    {:error, [minute: {:could_not_parse_field, ["423"]}]}

# `next`

```elixir
@spec next(dt :: nil | DateTime.t(), input :: binary(), opts :: keyword()) ::
  DateTime.t()
```

Returns the next `DateTime` the respective `cron` record points to
with a precision given as the third argument (default: `:second`.)

If the first parameter is not given, it assumes _the next after now_.

_Examples_

    iex> dt = DateTime.from_unix!(1567091960)
    ~U[2019-08-29 15:19:20Z]
    iex> Tempus.Crontab.next(dt, "42 3 28 08 *")
    [
      origin: ~U[2019-08-29 15:19:20Z],
      next: ~U[2020-08-28 03:42:00Z],
      second: 31494160
    ]

where `origin` contains the timestamp to lookup the `next` for, `next`
is the `DateTime` instance of the next event and `second` is the
{`precision`, `difference_in_that_precision`}.

# `next_as_list`

```elixir
@spec next_as_list(dt :: nil | DateTime.t(), input :: binary(), opts :: keyword()) ::
  keyword()
```

Returns the _list_ of all the events after `dt` (default: `DateTime.utc_now/0`.)

This function calculates the outcome greedily and, while it might be slightly
faster than `Tempus.Crontab.next_as_stream/3`, it should not be used for
frequently recurring cron records (like `"* * * * *"`.)

# `next_as_stream`

```elixir
@spec next_as_stream(dt :: nil | DateTime.t(), input :: binary(), opts :: keyword()) ::
  Enumerable.t()
```

Returns the _stream_ of all the events after `dt` (default: `DateTime.utc_now/0`.)

This function calculates the outcome lazily, returning a stream.

See `Tempus.Crontab.next_as_list/3` for greedy evaluation.

### Examples

    iex> ~U[2024-06-07 12:00:00Z] |> Tempus.Crontab.next_as_stream("10-30/5 */4 1 */1 6,7") |> Enum.take(2)
    [
      [origin: ~U[2024-06-07 12:00:00Z], next: ~U[2024-06-08 00:10:00Z], second: 43800],
      [origin: ~U[2024-06-07 12:00:00Z], next: ~U[2024-06-08 00:15:00Z], second: 44100]
    ]

# `parse`

```elixir
@spec parse(input :: binary()) :: t()
```

Parses the cron string into human-readable representation.

**This function is exported for debugging purposes only, normally one would call `prepare/1` instead.**

Input format: ["minute hour day/month month day/week"](https://crontab.guru/).

_Examples:_

    iex> Tempus.Crontab.parse "10-30/5 */4 1 */1 6,7"
    %Tempus.Crontab{
      day: "(day == 1)",
      day_of_week: "(day_of_week == 6 || day_of_week == 7)",
      hour: "(rem(hour, 4) == 0)",
      minute: "(rem(minute, 5) == 0 && minute >= 10 && minute <= 30)",
      month: "(rem(month, 1) == 0)"
    }

_In case of malformed input:_

    iex> Tempus.Crontab.parse "10-30/5 */4 1 */1 6d,7"
    %Tempus.Crontab{
      day: "(day == 1)",
      day_of_week: {:error, {:could_not_parse_integer, "6d"}},
      hour: "(rem(hour, 4) == 0)",
      minute: "(rem(minute, 5) == 0 && minute >= 10 && minute <= 30)",
      month: "(rem(month, 1) == 0)"
    }

# `prepare`

```elixir
@spec prepare(input :: binary() | t()) :: t()
```

Parses the cron string into `Tempus.Crontab.t()` struct.

Input format: ["minute hour day/month month day/week"](https://crontab.guru/).

# `to_cron`

```elixir
@spec to_cron(dt :: Time.t()) :: binary()
```

Converts the `Time` instance into daily-execution cron string

---

*Consult [api-reference.md](api-reference.md) for complete listing*
