defprotocol Timex.Comparable do @moduledoc """ This protocol is used for comparing and diffing different date/time representations """ alias Timex.Types @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 @type constants :: :epoch | :zero | :distant_past | :distant_future @type comparable :: Date.t() | DateTime.t() | NaiveDateTime.t() | Types.date() | Types.datetime() @type compare_result :: -1 | 0 | 1 | {:error, term} @type diff_result :: Timex.Duration.t() | integer | {:error, term} @doc """ Compare two date or datetime types. You can optionally specify a comparison granularity, any of 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 (default) - :microseconds - :duration and the dates will be compared with the cooresponding accuracy. The default granularity is `: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 """ @spec compare(comparable, comparable, granularity) :: compare_result def compare(a, b, granularity \\ :microsecond) @doc """ Get the difference between two date or datetime types. You can optionally specify a diff granularity, any of 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 (default) - :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 """ @spec diff(comparable, comparable, granularity) :: diff_result def diff(a, b, granularity \\ :microsecond) end