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

The components of a duration that is one of the amounts of a set (D-109).

A duration with a set (`{:years_and_months_duration, set}`, `{:days_and_time_duration, set}`, D-109) is one of
the amounts of the set: whole months, or seconds with a fraction (`Feel.Type.Image`). The properties of Table 67
are worked out from the **magnitude** of the amount and take its sign, as `Feel.Runtime.Path` does:

| Property  | Of a magnitude `m`                                                                              |
| --------- | ----------------------------------------------------------------------------------------------- |
| `years`   | the whole years of `m` months: `m div 12`                                                       |
| `months`  | what is left of them: `m rem 12`                                                                |
| `days`    | the whole days of the whole seconds `w` of `m`: `w div 86400`                                   |
| `hours`   | the whole hours of what is left of `w` in a day: `(w rem 86400) div 3600`                       |
| `minutes` | the whole minutes of what is left of `w` in an hour: `(w rem 3600) div 60`                      |
| `seconds` | `m` less its whole minutes, with the fraction: `m` modulo 60                                    |
| `value`   | the amount itself, so the set                                                                   |

The set is split at zero, into the amounts that are not below it and those that are, whose magnitudes are the
other way round; the properties of each are worked out as the magnitudes of an interval, and the sign is
put back. The numbers are exact (whole numbers and fractions of a power of ten), so a bound of the set that
is a multiple of a day or of a minute is kept as one, and an interval that is open there leaves out what it
does.

A property that is a whole number is exact: every number of the type is the property of some amount of the set,
and only a long interval has all of the values of a remainder (`months` of a range of 12 months or more, `hours`
of one of a day, `minutes` of one of an hour). `seconds` is a set of numbers in `[0..60)` that is exact for the
amounts of a set of numbers; the amounts of a duration are as fine as a number goes. A bound of more than 34
digits is the end of the range of numbers (`Feel.Analysis.IntegerSet`).

    iex> set = Feel.Type.NumberSet.interval(Decimal.new(3_600), Decimal.new(90_000))
    iex> {:ok, hours} = Feel.Analysis.DurationProperties.select(:days_and_time_duration, set, "hours")
    iex> Feel.Type.Union.format(hours)
    "number in [0..23]"
    iex> {:ok, days} = Feel.Analysis.DurationProperties.select(:days_and_time_duration, set, "days")
    iex> Feel.Type.Union.format(days)
    "number in [0..1]"
    iex> negative = Feel.Type.NumberSet.interval(Decimal.new(-7_300), Decimal.new(-3_700))
    iex> {:ok, hours} = Feel.Analysis.DurationProperties.select(:days_and_time_duration, negative, "hours")
    iex> Feel.Type.Union.format(hours)
    "number in [-2..-1]"

# `restrict`

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

The amounts of the set whose component `key` 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/3`: a condition says what a component is (`s.hours > 2`),
`members` is the type that it leaves of the component, and the duration is one of the amounts of the set that have it.

The amounts are the magnitudes of the set with their sign, as in `select/3`, and the magnitudes that have a component are
found by what the component is of one: the whole years of a month, or the whole days of a second, are a block of
them (`years` 2 is the months 24 to 35, `days` 1 the seconds from 86400 up to 172800); an hour, a minute or a month is one
block in each cycle of a day, an hour or a year; the seconds are an interval in each minute. Those of a negative amount
are the reflection of those of its magnitude, with the numbers of the component reflected too. `value` is the amount
itself, so the set that the fact leaves.

So the amounts left are exact, but for a set of numbers keeping 16 pieces at most and replacing more by the one that
holds them all, which is a larger set and so a sound one. A set of more than 2,000 cycles is `:error`, and left as it is.

    iex> set = Feel.Type.NumberSet.interval(Decimal.new(3_600), Decimal.new(18_000))
    iex> later = [{:number, Feel.Type.NumberSet.interval(Decimal.new(3), Decimal.new(100))}]
    iex> {:ok, amounts} = Feel.Analysis.DurationProperties.restrict(:days_and_time_duration, set, "hours", later)
    iex> Feel.Type.Union.format([{:days_and_time_duration, amounts}])
    "days and time duration in [PT3H..PT5H]"

# `select`

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

The type of the property `key` of a duration of `kind` that is one of the amounts of the set, or `:error` if
the kind has no such property, or the set has no amount that has one (a set of months that holds no whole number).

---

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