Without adding a dependency like Timex, the following works for adding/subtracting Gregorian months without too much trouble - assuming you only need the first of each month. Shifting to a day of the month directly may be best served through a library, given how many calendrical fallacies there are.
defmodule DateUtils
@doc """
Shift a given date forward or back n months
"""
def shift_n_months(date, n) when n < 0, do: subtract_n_months(date, -1 * n)
def shift_n_months(date, n), do: add_n_months(date, n)
def add_n_months(date, 0), do: Date.beginning_of_month(date)
def add_n_months(date, n) do
date
|> Date.end_of_month()
|> Date.add(1)
|> add_n_months(n - 1)
end
def subtract_n_months(date, 0), do: Date.beginning_of_month(date)
def subtract_n_months(date, n) do
date
|> Date.beginning_of_month()
|> Date.add(-1)
|> subtract_n_months(n - 1)
end
end
Enum.reduce(1..n, date, fn _, acc -> previous_month(acc) end)
? – Sarazenprevious_month(acc)
are you going to make? I thought the idea would be to make just one call – ApportionEnum.reduce(1..n, date, fn _, acc -> previous_month(acc) end)
. You are doingEnum.reduce(1..n, ...
meaning you are going to callprevious_month(acc)
at leastn
times. That is what i meant by n calls – Apportion