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

The year, month, day, weekday and value of a date that is one of the days of a set (D-109).

A date with a set (`{:date, set}`, D-109) is one of the days of the set, the days of the proleptic Gregorian
calendar that `Feel.Type.Image` numbers. So the properties of Table 67 that it can have are the properties of
those days, and `select/2` computes them: `year` of a date in `[2020-01-01..2020-12-31]` is `2020`, and `month`
of one in `[2020-01-01..2020-01-31]` is `1`.

| Property  | The set                                                                                       |
| --------- | --------------------------------------------------------------------------------------------- |
| `year`    | from the year of the first day of each interval to the year of its last: the year does not decrease with the day, so every year between is there |
| `month`, `day`, `weekday` | the values of the days of each interval, which are counted when it is no longer than 400 days; a longer one has every month, every day of a month and every weekday, so they are all of them |
| `value`   | from the seconds of midnight UTC of the first day of each interval to those of its last (D-68); a number that is not a multiple of a day is in it all the same, so it is a larger set than the days make |

The days of a set are the whole numbers in its intervals, so `(2020-01-01..2020-01-02)` has no day and `select/2`
has nothing to say about it: it is `:error`, and the caller gives the property of any date. A bound beyond the
days of the calendar is the first or the last day. The set is sound for every date it holds, and exact for
`year`, `month`, `day` and `weekday`: each number in it is the property of some day of the set (the numbers
between the ends of an interval are taken for whole, as every set of numbers is).

    iex> alias Feel.Type.NumberSet
    iex> days = NumberSet.interval(Decimal.new(Date.to_gregorian_days(~D[2020-01-01])), Decimal.new(Date.to_gregorian_days(~D[2020-03-31])))
    iex> {:ok, month} = Feel.Analysis.DateProperties.select(days, "month")
    iex> Feel.Type.Union.format(month)
    "number in [1..3]"
    iex> {:ok, year} = Feel.Analysis.DateProperties.select(days, "year")
    iex> Feel.Type.Union.format(year)
    "number = 2020"

# `keys`

```elixir
@spec keys() :: [String.t(), ...]
```

The properties of a date that `select/2` knows.

# `restrict`

```elixir
@spec restrict(Feel.Type.NumberSet.t(), String.t(), [Feel.Type.Union.member()]) ::
  {:ok, Feel.Type.NumberSet.t()} | :error
```

The days of the set whose `year`, `month`, `day` or `weekday` is one of the numbers that `members` has, or `:error` if
they are not worked out (D-194). It is the other way round from `select/2`: a condition says what the property of a
date is (`d.month > 6`), and `members` is the type that the condition leaves of the property, so the date is one of
the days of the set that have it.

The days that are left are exact for a `year` (the years are in a row), for a `month` and a `day` (the months of the
set are walked, up to a hundred years of them), and are, for a `weekday`, from the first to the last of the days of
each interval that have one of them: there are too many other days to keep apart, so a day between may be of another
weekday, which is a larger set and so a sound one. The set is sound in every case: a day that is left out has none of
the numbers. A set with a hundred years of months or more is `:error` for a `month` and a `day`, and is left as it is.

    iex> alias Feel.Type.NumberSet
    iex> year = NumberSet.interval(Decimal.new(Date.to_gregorian_days(~D[2020-01-01])), Decimal.new(Date.to_gregorian_days(~D[2020-12-31])))
    iex> later = [{:number, NumberSet.interval({Decimal.new(6), :open}, Decimal.new(12))}]
    iex> {:ok, days} = Feel.Analysis.DateProperties.restrict(year, "month", later)
    iex> Feel.Type.Union.format([{:date, days}])
    "date in [2020-07-01..2020-12-31]"

# `select`

```elixir
@spec select(Feel.Type.NumberSet.t(), String.t()) ::
  {:ok, Feel.Type.Union.t()} | :error
```

The type of the property `key` of a date in the set of days, or `:error` if the set has no day.

# `whole_days`

```elixir
@spec whole_days(Feel.Type.NumberSet.t()) :: [{integer(), integer()}]
```

The whole days in a set of numbers, within the days of the calendar, as ranges `{first, last}` of day numbers.

    iex> set = Feel.Type.NumberSet.interval({Decimal.new("0.5"), :closed}, {Decimal.new(3), :open})
    iex> Feel.Analysis.DateProperties.whole_days(set)
    [{1, 2}]

---

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