# `Feel.Type.Image`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/type/image.ex#L1)

The numbers that stand for the values of a date or a duration, so that their sets can be sets
of numbers (D-109).

A `Feel.Type.NumberSet` is a set of numbers in intervals, and the algebra on it
(`Feel.Analysis.Intervals`) is that of numbers. A date and the two kinds of duration are
ordered and, for the durations, added, subtracted, multiplied and divided as numbers are, so
`Feel.Type.Union` holds their sets as sets of numbers too: `{:date, set}`,
`{:years_and_months_duration, set}` and `{:days_and_time_duration, set}`. What the numbers
of the set are is the **image** of the values:

| Kind                        | The image of a value                               |
| --------------------------- | -------------------------------------------------- |
| `date`                      | its number of days in the proleptic Gregorian calendar (`Date.to_gregorian_days/1`: 0 is 0000-01-01) |
| `years and months duration` | its number of months                               |
| `days and time duration`    | its number of seconds                              |
| `time`, `date and time`     | the whole second it falls in, on a line for the values with no zone and a line for those with one (`Feel.Type.Moment`, D-109) |

The image of a date or a duration is one-to-one and keeps the order, so `a < b` for two values is `<` for their images,
and `a = b` is `=`. For the durations it keeps the operations too: the image of `a + b` is the
sum of the images, and the image of `a * n` is the image of `a` times `n`. Two dates are as many
days apart as their images are, so `date - date` has a set too. The image does not carry the
other temporal operations: a date plus months has its day clamped to the month, and a years and
months duration times a number is rounded, so the image of the result is not a sum of images
(D-54). That of a time and a date and time is neither: it is the second, and the order of two depends on a zone
(`Feel.Type.Moment`).

The set of every value of a kind is its **universe**. For the durations it is every number of
decimal128, since a duration is as large as a number can be, and for a date it is the days from
-999,999,999-01-01 to 999,999,999-12-31. A set that holds the universe is the bare kind
(`Feel.Type.Union`).

A set is written as the values it has: `P1DT2H`, `[PT0S..P1D]`, `2024-01-31`.

    iex> Feel.Type.Image.image(Feel.Value.DaysAndTimeDuration.new(93_600))
    Decimal.new("93600")
    iex> Feel.Type.Image.image(~D[0000-01-02])
    Decimal.new("1")
    iex> Feel.Type.Image.format_value(:days_and_time_duration, Decimal.new(93_600))
    "P1DT2H"

# `kind`

```elixir
@type kind() ::
  :date
  | :years_and_months_duration
  | :days_and_time_duration
  | :time
  | :date_and_time
```

A kind whose sets are sets of images.

# `covers?`

```elixir
@spec covers?(kind() | :number, Feel.Type.NumberSet.t()) :: boolean()
```

Returns `true` when the set has every value of the kind.

    iex> Feel.Type.Image.covers?(:date, Feel.Type.Image.universe(:date))
    true
    iex> Feel.Type.Image.covers?(:date, Feel.Type.NumberSet.point(Decimal.new(0)))
    false

# `format_set`

```elixir
@spec format_set(kind(), Feel.Type.NumberSet.t()) :: String.t()
```

Writes a set of images as the values it has, as `Feel.Type.NumberSet.format/2` does for numbers.

    iex> set = Feel.Type.NumberSet.interval(Decimal.new(0), Decimal.new(86_400))
    iex> Feel.Type.Image.format_set(:days_and_time_duration, set)
    "[PT0S..P1D]"

# `format_value`

```elixir
@spec format_value(kind(), Decimal.t()) :: String.t()
```

Writes the value that an image stands for: a date as `2024-01-31`, a years and months duration as
`P1Y2M`, a days and time duration as `P1DT2H3M4.5S`. A number that is not the image of a value, as
half a month is not, is written as the number.

    iex> Feel.Type.Image.format_value(:date, Decimal.new(739_281))
    "2024-01-31"
    iex> Feel.Type.Image.format_value(:years_and_months_duration, Decimal.new(14))
    "P1Y2M"
    iex> Feel.Type.Image.format_value(:years_and_months_duration, Decimal.new(-12))
    "-P1Y"
    iex> Feel.Type.Image.format_value(:days_and_time_duration, Decimal.new("0.5"))
    "PT0.5S"
    iex> Feel.Type.Image.format_value(:days_and_time_duration, Decimal.new(0))
    "PT0S"
    iex> Feel.Type.Image.format_value(:days_and_time_duration, Decimal.new("-5E+40"))
    "-PT5E+40S"

# `image`

```elixir
@spec image(
  Date.t()
  | Feel.Value.YearsAndMonthsDuration.t()
  | Feel.Value.DaysAndTimeDuration.t()
) ::
  Decimal.t()
```

The image of a date or a duration.

    iex> Feel.Type.Image.image(Feel.Value.YearsAndMonthsDuration.new(-14))
    Decimal.new("-14")

# `kinds`

```elixir
@spec kinds() :: [kind(), ...]
```

The kinds whose sets are sets of images: `:date`, the two durations, `:time` and `:date_and_time`.

# `universe`

```elixir
@spec universe(kind() | :number) :: Feel.Type.NumberSet.t()
```

The set of the images of every value of a kind. A number is its own image, so the universe of
`:number` is every number.

    iex> Feel.Type.Image.universe(:days_and_time_duration) == Feel.Type.NumberSet.all()
    true
    iex> Feel.Type.NumberSet.format(Feel.Type.Image.universe(:date))
    "[-365242499634..365242499999]"

---

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