# `Feel.Analysis.DatePreimage`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/analysis/date_preimage.ex#L1)

The dates and the durations that give a date in a set when one is added to the other (D-122).

`Feel.Analysis.DateArithmetic` goes from a date and a duration to the dates they give. This goes the other way, for
`d + p > @"2020-06-01"`: given the days that the sum is in, the operator and the amounts or the dates that the other
operand is, `dates/4` gives the days that the date can be, and `amounts/4` the seconds or the months that the
duration can be.

The run adds a duration to a date in two ways (`Feel.Runtime.Temporal`), and both are whole days and do not
decrease when the date does or the duration does:

  * A **days and time duration** adds the whole days of its seconds, rounded down: `floor(seconds / 86400)`, so
    36 hours are a day and minus one second is minus a day. The days a date can be are the days of the set less
    the days of the amounts, and the seconds a duration can be are the seconds of whole days from the days of the
    set less the dates (the last of them is a second short of the next day, so that end is open). Both are exact.
  * A **years and months duration** adds its months to the month of the date and cuts the day to the length of
    the month: `2021-01-31` plus `P1M` is `2021-02-28`. The function does not decrease, so the least date that
    gives a day or more, and the greatest that gives a day or less, are found by a search, and the dates in
    between are the dates that give a day in the set. For each month of the duration that is a piece, up to 64
    of them, and the hull of the pieces past that, which holds more and so is sound. The months a duration can be
    are the least that gives a day or more at the last date and the greatest that gives a day or less at the
    first (a later date needs fewer months), which is exact for dates one after the other.

A subtraction adds the negative: a date less a duration is the date plus the amounts reflected.

    iex> alias Feel.Type.NumberSet
    iex> day = fn date -> Decimal.new(Date.to_gregorian_days(date)) end
    iex> result = NumberSet.interval(day.(~D[2021-03-01]), day.(~D[2021-03-31]))
    iex> month = NumberSet.point(Decimal.new(1))
    iex> dates = Feel.Analysis.DatePreimage.dates(:add, :years_and_months_duration, result, month)
    iex> Feel.Type.Union.format([{:date, dates}])
    "date in [2021-02-01..2021-02-28]"

# `amounts`

```elixir
@spec amounts(
  :add | :subtract,
  :years_and_months_duration | :days_and_time_duration,
  Feel.Type.NumberSet.t(),
  Feel.Type.NumberSet.t()
) :: Feel.Type.NumberSet.t()
```

The amounts that a duration of a kind can be, when its sum with (`:add`) or its difference from (`:subtract`) a date
of the days is a day of the results.

# `dates`

```elixir
@spec dates(
  :add | :subtract,
  :years_and_months_duration | :days_and_time_duration,
  Feel.Type.NumberSet.t(),
  Feel.Type.NumberSet.t()
) :: Feel.Type.NumberSet.t()
```

The days that a date can be, when its sum with (`:add`) or its difference from (`:subtract`) a duration of the
amounts of a kind is a day of the results.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
