# `Timex.Interval`
[🔗](https://github.com/bitwalker/timex/blob/4.0.0/lib/interval/interval.ex#L1)

This module is used for creating and manipulating date/time intervals.

## Examples

    iex> use Timex
    ...> Interval.new(from: ~D[2016-03-03], until: [days: 3])
    %Elixir.Timex.Interval{from: ~N[2016-03-03 00:00:00], left_open: false, right_open: true, step: [days: 1], until: ~N[2016-03-06 00:00:00]}

    iex> use Timex
    ...> Interval.new(from: ~D[2016-03-03], until: ~N[2016-03-10 01:23:45])
    %Timex.Interval{from: ~N[2016-03-03 00:00:00], left_open: false, right_open: true, step: [days: 1], until: ~N[2016-03-10 01:23:45]}

    iex> use Timex
    ...> ~N[2016-03-04 12:34:56] in Interval.new(from: ~D[2016-03-03], until: [days: 3])
    true

    iex> use Timex
    ...> ~D[2016-03-01] in Interval.new(from: ~D[2016-03-03], until: [days: 3])
    false

    iex> use Timex
    ...> Interval.overlaps?(Interval.new(from: ~D[2016-03-01], until: [days: 5]),  Interval.new(from: ~D[2016-03-03], until: [days: 3]))
    true

    iex> use Timex
    ...> Interval.overlaps?(Interval.new(from: ~D[2016-03-01], until: [days: 1]),  Interval.new(from: ~D[2016-03-03], until: [days: 3]))
    false

# `t`

```elixir
@type t() :: %Timex.Interval{
  from: term(),
  left_open: term(),
  right_open: term(),
  step: term(),
  until: term()
}
```

# `valid_interval_step`

```elixir
@type valid_interval_step() :: {valid_step_unit(), integer()}
```

# `valid_interval_steps`

```elixir
@type valid_interval_steps() :: [valid_interval_step()]
```

# `valid_step_unit`

```elixir
@type valid_step_unit() ::
  :microseconds
  | :milliseconds
  | :seconds
  | :minutes
  | :hours
  | :days
  | :weeks
  | :months
  | :years
```

# `contains?`

```elixir
@spec contains?(t(), t()) :: boolean()
```

Returns true if the first interval includes every point in time the second includes.

## Examples

    iex> Elixir.Timex.Interval.contains?(Elixir.Timex.Interval.new(from: ~D[2018-01-01], until: ~D[2018-01-31]), Elixir.Timex.Interval.new(from: ~D[2018-01-01], until: ~D[2018-01-30]))
    true

    iex> Elixir.Timex.Interval.contains?(Elixir.Timex.Interval.new(from: ~D[2018-01-01], until: ~D[2018-01-30]), Elixir.Timex.Interval.new(from: ~D[2018-01-01], until: ~D[2018-01-31]))
    false

    iex> Elixir.Timex.Interval.contains?(Elixir.Timex.Interval.new(from: ~D[2018-01-01], until: ~D[2018-01-10]), Elixir.Timex.Interval.new(from: ~D[2018-01-05], until: ~D[2018-01-15]))
    false

# `difference`

```elixir
@spec difference(t(), t()) :: [t()]
```

Removes one interval from another which may reduce, split, or
eliminate the original interval. Returns a (possibly empty) list
of intervals representing the remaining time.

## Graphs

The following textual graphs show all the ways that the original interval and
the removal can relate to each other, and the action that `difference/2` will
take in each case.
The original interval is drawn with `O`s and the removal interval with `X`s.

    # return original
    OO
        XX

    # trim end
    OOO
      XXX

    # trim end
    OOOOO
      XXX

    # split
    OOOOOOO
      XXX

    # eliminate
    OO
    XX

    # eliminate
    OO
    XXXX

    # trim beginning
    OOOO
    XX

    # eliminate
      OO
    XXXXXX

    # eliminate
        OO
    XXXXXX

    # trim beginning
      OOO
    XXX

    # return original
         OO
    XX

## Examples

    iex> Elixir.Timex.Interval.difference(Elixir.Timex.Interval.new(from: ~N[2018-01-01 02:00:00.000], until: ~N[2018-01-01 04:00:00.000]), Elixir.Timex.Interval.new(from: ~N[2018-01-01 03:00:00.000], until: ~N[2018-01-01 05:00:00.000]))
    [%Elixir.Timex.Interval{from: ~N[2018-01-01 02:00:00.000], left_open: false, right_open: true, step: [days: 1], until: ~N[2018-01-01 03:00:00.000]}]

    iex> Elixir.Timex.Interval.difference(Elixir.Timex.Interval.new(from: ~N[2018-01-01 01:00:00.000], until: ~N[2018-01-01 05:00:00.000]), Elixir.Timex.Interval.new(from: ~N[2018-01-01 02:00:00.000], until: ~N[2018-01-01 03:00:00.000]))
    [%Elixir.Timex.Interval{from: ~N[2018-01-01 01:00:00.000], left_open: false, right_open: true, step: [days: 1], until: ~N[2018-01-01 02:00:00.000]}, %Elixir.Timex.Interval{from: ~N[2018-01-01 03:00:00.000], left_open: false, right_open: true, step: [days: 1], until: ~N[2018-01-01 05:00:00.000]}]

    iex> Elixir.Timex.Interval.difference(Elixir.Timex.Interval.new(from: ~N[2018-01-01 02:00:00.000], until: ~N[2018-01-01 04:00:00.000]), Elixir.Timex.Interval.new(from: ~N[2018-01-01 01:00:00.000], until: ~N[2018-01-01 05:00:00.000]))
    []

# `duration`

Return the interval duration, given a unit.

When the unit is one of `:seconds`, `:minutes`, `:hours`, `:days`, `:weeks`, `:months`, `:years`, the result is an `integer`.

When the unit is `:duration`, the result is a `Duration` struct.

## Example

    iex> use Timex
    ...> Interval.new(from: ~D[2014-09-22], until: [months: 5])
    ...> |> Interval.duration(:months)
    5

    iex> use Timex
    ...> Interval.new(from: ~N[2014-09-22T15:30:00], until: [minutes: 20])
    ...> |> Interval.duration(:duration)
    Duration.from_minutes(20)

# `format`

Formats the interval as a human readable string.

## Examples

    iex> use Timex
    ...> Interval.new(from: ~D[2014-09-22], until: [days: 3])
    ...> |> Interval.format!("%Y-%m-%d %H:%M", :strftime)
    "[2014-09-22 00:00, 2014-09-25 00:00)"

    iex> use Timex
    ...> Interval.new(from: ~D[2014-09-22], until: [days: 3])
    ...> |> Interval.format!("%Y-%m-%d", :strftime)
    "[2014-09-22, 2014-09-25)"

# `format!`

Same as `format/3`, but raises a `Timex.Interval.FormatError` on failure.

# `new`

```elixir
@spec new(Keyword.t()) :: t() | {:error, :invalid_until} | {:error, :invalid_step}
```

Create a new Interval struct.

**Note:** By default intervals are left closed, i.e. they include the `from` date/time,
and exclude the `until` date/time. Put another way, `from <= x < until`. This behavior
matches that of other popular date/time libraries, such as Joda Time, as well as the SQL
behavior of the `overlaps` keyword.

Options:

- `from`: The date the interval starts at. Should be a `(Naive)DateTime`.
- `until`: Either a `(Naive)DateTime`, or a time shift that will be applied to the `from` date.
  This value must be greater than `from`, or equal to it when both bounds are closed.
  Equal closed bounds represent a singleton interval; all other equal or reversed bounds return an error.
- `left_open`: Whether the interval is left open. See explanation below.
- `right_open`: Whether the interval is right open. See explanation below.
- `step`: The step to use when iterating the interval, defaults to `[days: 1]`

The terms `left_open` and `right_open` come from the mathematical concept of intervals. You
can see more detail on the theory [on Wikipedia](https://en.wikipedia.org/wiki/Interval_(mathematics)),
but it can be more intuitively thought of like so:

- An "open" bound is exclusive, and a "closed" bound is inclusive
- So a left-closed interval includes the `from` value, and a left-open interval does not.
- Likewise, a right-closed interval includes the `until` value, and a right-open interval does not.
- An open interval is both left and right open, conversely, a closed interval is both left and right closed.

**Note:** `until` shifts delegate to `Timex.shift`, so the options provided should match its valid options.

## Examples

    iex> use Timex
    ...> Interval.new(from: ~D[2014-09-22], until: ~D[2014-09-29])
    ...> |> Interval.format!("%Y-%m-%d", :strftime)
    "[2014-09-22, 2014-09-29)"

    iex> use Timex
    ...> Interval.new(from: ~D[2014-09-22], until: [days: 7])
    ...> |> Interval.format!("%Y-%m-%d", :strftime)
    "[2014-09-22, 2014-09-29)"

    iex> use Timex
    ...> Interval.new(from: ~D[2014-09-22], until: [days: 7], left_open: true, right_open: false)
    ...> |> Interval.format!("%Y-%m-%d", :strftime)
    "(2014-09-22, 2014-09-29]"

    iex> use Timex
    ...> Interval.new(from: ~N[2014-09-22T15:30:00], until: [minutes: 20], right_open: false)
    ...> |> Interval.format!("%H:%M", :strftime)
    "[15:30, 15:50]"

# `overlaps?`

```elixir
@spec overlaps?(t(), t()) :: boolean()
```

Returns true if the first interval shares any point(s) in time with the second.

## Examples

    iex> Elixir.Timex.Interval.overlaps?(Elixir.Timex.Interval.new(from: ~D[2016-03-04], until: [days: 1]), Elixir.Timex.Interval.new(from: ~D[2016-03-03], until: [days: 3]))
    true

    iex> Elixir.Timex.Interval.overlaps?(Elixir.Timex.Interval.new(from: ~D[2016-03-07], until: [days: 1]), Elixir.Timex.Interval.new(from: ~D[2016-03-03], until: [days: 3]))
    false

# `with_step`

```elixir
@spec with_step(t(), valid_interval_steps()) :: t() | {:error, :invalid_step}
```

Change the step value for the provided interval.

The step should be a keyword list valid for use with `Timex.Date.shift`.

## Examples

    iex> use Timex
    ...> Interval.new(from: ~D[2014-09-22], until: [days: 3], right_open: true)
    ...> |> Interval.with_step([days: 1]) |> Enum.map(&Timex.format!(&1, "%Y-%m-%d", :strftime))
    ["2014-09-22", "2014-09-23", "2014-09-24"]

    iex> use Timex
    ...> Interval.new(from: ~D[2014-09-22], until: [days: 3], right_open: false)
    ...> |> Interval.with_step([days: 1]) |> Enum.map(&Timex.format!(&1, "%Y-%m-%d", :strftime))
    ["2014-09-22", "2014-09-23", "2014-09-24", "2014-09-25"]

    iex> use Timex
    ...> Interval.new(from: ~D[2014-09-22], until: [days: 3], right_open: false)
    ...> |> Interval.with_step([days: 2]) |> Enum.map(&Timex.format!(&1, "%Y-%m-%d", :strftime))
    ["2014-09-22", "2014-09-24"]

    iex> use Timex
    ...> Interval.new(from: ~D[2014-09-22], until: [days: 3], right_open: false)
    ...> |> Interval.with_step([days: 3]) |> Enum.map(&Timex.format!(&1, "%Y-%m-%d", :strftime))
    ["2014-09-22", "2014-09-25"]

---

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