# `Feel.Value.DateTime`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/value/date_time.ex#L1)

The FEEL type `date and time` (DMN 1.6, section 10.3.2.3.6): a date together
with a time of day.

It is a `Feel.Value.Date` plus a `Feel.Value.Time`. Elixir's `DateTime` is not
used because it has microsecond precision and needs a time zone database to
normalize values, while FEEL needs nanosecond precision and has to keep the
original zone form (floating, offset, or IANA) to compare and format values
correctly.

## Fields

  * `:date` - a `t:Feel.Value.Date.t/0`.
  * `:time` - a `t:Feel.Value.Time.t/0`, with its zone.

# `t`

```elixir
@type t() :: %Feel.Value.DateTime{
  date: Feel.Value.Date.t(),
  time: Feel.Value.Time.t()
}
```

# `new`

```elixir
@spec new(Feel.Value.Date.t(), Feel.Value.Time.t()) :: {:ok, t()} | :error
```

Combines a date and a time.

Returns `:error` when the date or the time is not a valid FEEL value, such as a
year outside the FEEL range.

    iex> {:ok, time} = Feel.Value.Time.new(0, 0, 0, {:offset, 0})
    iex> {:ok, date_time} = Feel.Value.DateTime.new(~D[2026-10-12], time)
    iex> date_time.date
    ~D[2026-10-12]
    iex> Feel.Value.DateTime.new(Date.new!(1_000_000_000, 1, 1), time)
    :error

# `parse`

```elixir
@spec parse(String.t()) :: {:ok, t()} | :error
```

Parses a date and time string, as `date and time("...")` and `@"..."` read it: a date
string, optionally followed by `T` and a time string (DMN 1.6, section 10.3.4.1).

The time string is read as `Feel.Value.Time.parse/1` reads it, so the value has the
zone that the string gives: none (floating), an offset, or an IANA zone id; and a time of
`24:00:00` is the start of the next day. A date alone is midnight with no zone, as the TCK
has it (`date and time("2012-12-24")` is `2012-12-24T00:00:00`, case `1117#007`), and not the
UTC midnight that the conversion of a date to a date and time in an operation gives
(notes 06, AE-12; D-54). A date followed by a zone is midnight in that zone, with the forms of a time
string: `Z`, an offset, `@` and the id of a zone. It is the one example of the specification for the
properties, `date and time("2012-03-07Z").year` (Table 65, printed `2012-0307Z`; D-68). Returns `:error`
for anything else.

    iex> {:ok, date_time} = Feel.Value.DateTime.parse("2012-12-24T23:59:00")
    iex> {date_time.date, date_time.time.hour, date_time.time.zone}
    {~D[2012-12-24], 23, :floating}
    iex> {:ok, date_time} = Feel.Value.DateTime.parse("2012-12-25T11:00:00Z")
    iex> date_time.time.zone
    {:offset, 0}
    iex> {:ok, date_time} = Feel.Value.DateTime.parse("2024-12-24T23:59:00@America/Costa_Rica")
    iex> date_time.time.zone
    {:iana, "America/Costa_Rica"}
    iex> {:ok, date_time} = Feel.Value.DateTime.parse("2012-12-24")
    iex> {date_time.time.hour, date_time.time.zone}
    {0, :floating}
    iex> {:ok, date_time} = Feel.Value.DateTime.parse("2012-03-07Z")
    iex> {date_time.date, date_time.time.hour, date_time.time.zone}
    {~D[2012-03-07], 0, {:offset, 0}}
    iex> {:ok, date_time} = Feel.Value.DateTime.parse("2012-03-07-05:00")
    iex> date_time.time.zone
    {:offset, -18000}
    iex> Feel.Value.DateTime.parse("2012-03-07 Z")
    :error
    iex> {:ok, date_time} = Feel.Value.DateTime.parse("2012-12-24T24:00:00")
    iex> {date_time.date, date_time.time.hour}
    {~D[2012-12-25], 0}
    iex> Feel.Value.DateTime.parse("2012-12-24T")
    :error
    iex> Feel.Value.DateTime.parse("2012-12-24T 10:00:00")
    :error

# `type`

```elixir
@spec type() :: Feel.Type.t()
```

Returns the type descriptor of `date and time`.

# `value?`

```elixir
@spec value?(term()) :: boolean()
```

Returns `true` for a `t:t/0` whose date and time are both valid.

---

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