The Calendar library has functionality for comparing dates and datetimes.
Calendar.Date module has a function for getting the difference
between two dates. You can for instance pass date tuples
or Calendar structs to the
Calendar.Date.diff/2 funciton. This will return the difference in days
between the two dates.
Ecto is another library that has structs for dates and datetimes.
To get an Ecto date struct you can use the
Ecto.Date.from_erl function like this:
What if you could use the same function in the calendar library to compare
Ecto.Date structs? You can!
The Calecto library contains a protocol implementation that makes this possible. It looks like this:
This means that if you have added Calecto to your Elixir project, you can pass Ecto.Date structs to the same function:
In the above example an Ecto.Date struct is compared to a tuple.
Whatever implements the
ContainsDate protocol can be used as parameters.
We can also compare two Ecto.Date structs:
All the other functions
But that is not all.
diff/2 is just one of the functions in the
Any place where a date is expected you can use
or tuples as you please. In addition to that you can implement the
Calendar.ContainsDate for your own custom
Those are just a few examples of the available functionality.
Comparing Ecto.DateTime structs
Ecto.DateTime structs have datetimes, but no timezone information
they are equivalent to Calendars
Calendar.Date functions take arguments that implement the
Calendar.NaiveDateTime functions take arguments that implement the
Calendar.ContainsNaiveDateTime protocol. Out of the box Calendar has implemented
these protocols for
Calendar.NaiveDateTime structs and erlang style tuples.
Calecto implements the protocol for
This means we can use the
Calendar.NaiveDateTime.diff/2 function to compare
Ecto.DateTime structs too.
The difference between the two structs is 603 seconds and 0 microseconds.
You can pattern match on the fourth tuple element to get
Alternatively if you do not want to know how big the difference is, but just want
to know if the first datetime is before the second one or not, there is a function for that:
And as with the
Date module you can also use
Ecto.DateTimes in the other functions
Comparing just the date part of a datetime
Ecto.Datetime contains a date - the
ContainsDate protocol is also implemented for
Ecto.Datetime. As with a simple date we can also use
the functions in the
Calendar.Date module with an
Ecto.DateTime as an argument.
What if you have two datetimes and you want to know if they are on the same date - not
if they are on the exact same time, just if they are on the same date. There is not a special
function for that made for date-times. Instead we can simply use the same function as before:
Date.diff/2. When passing datetimes, the protocols simply discards the time and just
uses the date part of the date-time:
How to get all of this goodness
The whole way
So far we have seen how the protocols effortlessly allow using date and time types from Ecto with Calendar modules.
With Elixir protocols it is possible to build functionality once in one library and then use it with data from other libraries without changing a single line of code in either! All you have to do is implement the necessary protocols. In this example those libraries are Calendar and Ecto. And Calecto provides the protocol implementation.
Even within one library the protocols provide a clean way of making one function usable with different data-types.