Skip to content

Instantly share code, notes, and snippets.

@Jeweller-Tsai
Created August 6, 2016 09:16
Show Gist options
  • Save Jeweller-Tsai/ffe3fb1344356ac33332696e6b7da5d5 to your computer and use it in GitHub Desktop.
Save Jeweller-Tsai/ffe3fb1344356ac33332696e6b7da5d5 to your computer and use it in GitHub Desktop.
defmodule ExclusiveDateRange do
defstruct first: nil, last: nil
def new(first, last) do
%ExclusiveDateRange{first: first, last: last}
end
defimpl Enumerable, for: ExclusiveDateRange do
def reduce _dr, {:halt, acc}, _fun do
{:halted, acc}
end
def reduce(dr, {:suspend, acc}, fun) do
{:suspended, acc, &reduce(dr, &1, fun)}
end
def reduce(%ExclusiveDateRange{first: d, last: d}, {:cont, acc}, _fun) do
{:done, acc}
end
def reduce(%ExclusiveDateRange{first: d1, last: d2}, {:cont, acc}, fun) do
reduce(%ExclusiveDateRange{first: next(d1), last: d2}, fun.(d1, acc), fun)
end
defp next %Date{year: y, month: m, day: d} do
case Date.new(y, m, d + 1) do
{:ok, nd} -> nd
{:error, :invalid_date} ->
case Date.new(y, m + 1, 1) do
{:ok, nd} -> nd
{:error, :invalid_date} ->
{:ok, nd} = Date.new(y + 1, 1, 1)
nd
end
end
end
def member?(%ExclusiveDateRange{first: d1, last: d2}, value) do
days1 = date_to_gregorian_days d1
days2 = date_to_gregorian_days(d2) - 1
days3 = date_to_gregorian_days value
{:ok, Enum.member?(days1..days2, days3)}
end
def count(%ExclusiveDateRange{first: d1, last: d2}) do
days1 = date_to_gregorian_days d1
days2 = date_to_gregorian_days d2
{:ok, days2 - days1}
end
defp date_to_gregorian_days date do
date |> Date.to_erl |> :calendar.date_to_gregorian_days
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment