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

This protocol is used for comparing and diffing different date/time representations

Built-in date implementations assume `Calendar.ISO` fields with years from
0 through 9999. Use the public `Timex.compare/3` and `Timex.diff/3` entrypoints
for input validation. Calendar differences also require UTC instants within
this range, independent of the local wall year.

# `comparable`

```elixir
@type comparable() ::
  Date.t()
  | DateTime.t()
  | NaiveDateTime.t()
  | Timex.Types.date()
  | Timex.Types.datetime()
```

# `compare_result`

```elixir
@type compare_result() :: -1 | 0 | 1 | {:error, term()}
```

# `constants`

```elixir
@type constants() :: :epoch | :zero | :distant_past | :distant_future
```

# `diff_result`

```elixir
@type diff_result() :: Timex.Duration.t() | integer() | {:error, term()}
```

# `granularity`

```elixir
@type granularity() ::
  :year
  | :years
  | :month
  | :months
  | :week
  | :weeks
  | :calendar_week
  | :calendar_weeks
  | :day
  | :days
  | :hour
  | :hours
  | :minute
  | :minutes
  | :second
  | :seconds
  | :millisecond
  | :milliseconds
  | :microsecond
  | :microseconds
  | :duration
```

# `t`

```elixir
@type t() :: term()
```

All the types that implement this protocol.

# `compare`

```elixir
@spec compare(comparable(), comparable(), granularity()) :: compare_result()
```

Compare two date or datetime types.

Specify a comparison granularity from the following:

- :year
- :years
- :month
- :months
- :week
- :weeks
- :calendar_week (weeks of the calendar as opposed to actual weeks in terms of days)
- :calendar_weeks
- :day
- :days
- :hour
- :hours
- :minute
- :minutes
- :second
- :seconds
- :millisecond
- :milliseconds
- :microsecond
- :microseconds
- :duration

and the dates will be compared with the corresponding accuracy.
The protocol requires an explicit granularity. `Timex.compare/2` and
`Timex.diff/2` default to `:microsecond`.

  - 0:  when equal
  - -1: when the first date/time comes before the second
  - 1:  when the first date/time comes after the second
  - `{:error, reason}`: when there was a problem comparing,
    perhaps due to a value being passed which is not a valid date/datetime

## Examples

    iex> use Timex
    iex> date1 = ~D[2014-03-04]
    iex> date2 = ~D[2015-03-04]
    iex> Timex.compare(date1, date2, :year)
    -1
    iex> Timex.compare(date2, date1, :year)
    1
    iex> Timex.compare(date1, date1)
    0

# `diff`

```elixir
@spec diff(comparable(), comparable(), granularity()) :: diff_result()
```

Get the difference between two date or datetime types.

Specify a diff granularity from the following:

- :year
- :years
- :month
- :months
- :week
- :weeks
- :calendar_week (weeks of the calendar as opposed to actual weeks in terms of days)
- :calendar_weeks
- :day
- :days
- :hour
- :hours
- :minute
- :minutes
- :second
- :seconds
- :millisecond
- :milliseconds
- :microsecond
- :microseconds
- :duration

and the result will be an integer value of those units or a Duration struct.
The diff value will be negative if `a` comes before `b`, and positive if `a` comes
after `b`. This behaviour mirrors `compare/3`.

When using granularity of :months, the number of days in the month varies. This
behavior mirrors `Timex.shift/2`.

## Examples

    iex> use Timex
    iex> date1 = ~D[2015-01-28]
    iex> date2 = ~D[2015-02-28]
    iex> Timex.diff(date1, date2, :month)
    -1
    iex> Timex.diff(date2, date1, :month)
    1

    iex> use Timex
    iex> date1 = ~D[2015-01-31]
    iex> date2 = ~D[2015-02-28]
    iex> Timex.diff(date1, date2, :month)
    -1
    iex> Timex.diff(date2, date1, :month)
    0

---

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