1defprotocol Timex.Comparable do
2  @moduledoc """
3  This protocol is used for comparing and diffing different date/time representations
4  """
5  alias Timex.Types
6
7  @type granularity :: :years | :months | :weeks | :calendar_weeks | :days |
8                       :hours | :minutes | :seconds | :milliseconds | :microseconds |
9                       :duration
10  @type constants :: :epoch | :zero | :distant_past | :distant_future
11  @type comparable :: Date.t | DateTime.t | NaiveDateTime.t | Types.date | Types.datetime
12  @type compare_result :: -1 | 0 | 1 | {:error, term}
13  @type diff_result :: Timex.Duration.t | integer | {:error, term}
14
15  @doc """
16  Compare two date or datetime types.
17
18  You can optionally specify a comparison granularity, any of the following:
19
20  - :years
21  - :months
22  - :weeks
23  - :calendar_weeks (weeks of the calendar as opposed to actual weeks in terms of days)
24  - :days
25  - :hours
26  - :minutes
27  - :seconds
28  - :milliseconds
29  - :microseconds (default)
30  - :duration
31
32  and the dates will be compared with the cooresponding accuracy.
33  The default granularity is :microseconds.
34
35    - 0:  when equal
36    - -1: when the first date/time comes before the second
37    - 1:  when the first date/time comes after the second
38    - {:error, reason}: when there was a problem comparing,
39      perhaps due to a value being passed which is not a valid date/datetime
40
41  ## Examples
42
43      iex> use Timex
44      iex> date1 = ~D[2014-03-04]
45      iex> date2 = ~D[2015-03-04]
46      iex> Timex.compare(date1, date2, :years)
47      -1
48      iex> Timex.compare(date2, date1, :years)
49      1
50      iex> Timex.compare(date1, date1)
51      0
52  """
53  @spec compare(comparable, comparable, granularity) :: compare_result
54  def compare(a, b, granularity \\ :microseconds)
55
56  @doc """
57  Get the difference between two date or datetime types.
58
59  You can optionally specify a diff granularity, any of the following:
60
61  - :years
62  - :months
63  - :calendar_weeks (weeks of the calendar as opposed to actual weeks in terms of days)
64  - :weeks
65  - :days
66  - :hours
67  - :minutes
68  - :seconds
69  - :milliseconds
70  - :microseconds (default)
71  - :duration
72
73  and the result will be an integer value of those units or a Duration struct.
74  The diff value will be negative if `a` comes before `b`, and positive if `a` comes
75  after `b`. This behaviour mirrors `compare/3`.
76
77  When using granularity of :months, the number of days in the month varies. This
78  behavior mirrors `Timex.shift/2`.
79
80  ## Examples
81
82      iex> use Timex
83      iex> date1 = ~D[2015-01-28]
84      iex> date2 = ~D[2015-02-28]
85      iex> Timex.diff(date1, date2, :months)
86      -1
87      iex> Timex.diff(date2, date1, :months)
88      1
89
90      iex> use Timex
91      iex> date1 = ~D[2015-01-31]
92      iex> date2 = ~D[2015-02-28]
93      iex> Timex.diff(date1, date2, :months)
94      -1
95      iex> Timex.diff(date2, date1, :months)
96      0
97  """
98  @spec diff(comparable, comparable, granularity) :: diff_result
99  def diff(a, b, granularity \\ :microseconds)
100end
101