# Narrowing a days and time duration

[Narrowing](../narrowing.md) › days and time duration. The names in the examples are those of [section 2](../narrowing.md#2-the-names-in-the-examples).

A `days and time duration` alternative is the bare kind or `{:days_and_time_duration, set}`: a `Feel.Type.NumberSet` of the **image** of the values, their number of **seconds**, with a fraction (`Feel.Type.Image`, D-109). The image is one-to-one and keeps the order, and for a duration it keeps the operations too: the image of `a + b` is the sum of the images, and of `a * n` the image of `a` times `n`. A days and time duration is a different kind from a years and months duration, and they are never compared.

## Comparisons

| Condition | `dd` when true | `dd` when not true |
| --- | --- | --- |
| `dd < @"PT1H"` | `days and time duration in [-max..PT1H)` | `days and time duration in [PT1H..max] \| Null` |
| `dd >= @"P1D"` | `days and time duration in [P1D..max]` | `days and time duration in [-max..P1D) \| Null` |
| `dd > @"PT0S"` | `days and time duration in (PT0S..max]` | `days and time duration in [-max..PT0S] \| Null` |
| `dd = @"PT0S"` | `days and time duration = PT0S` | `days and time duration in [-max..PT0S), (PT0S..max] \| Null` |
| `dd between @"PT1H" and @"PT2H"` | `days and time duration in [PT1H..PT2H]` | `days and time duration in [-max..PT1H), (PT2H..max] \| Null` |
| `dd < ym` | — | `days and time duration \| Null` |
| `dd instance of days and time duration` | `days and time duration` | `Null` |
| `dd instance of years and months duration` | — | `days and time duration \| Null` |

The `null` rules are those of every kind ([the rule](../narrowing.md#4-then-else-and-null)). `dd < ym` is never true: the kinds have no order between them.

## Properties

The components (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` seconds |
| --- | --- |
| `days` | the whole days: `w div 86400`, where `w` is the whole seconds of `m` |
| `hours` | the whole hours of what is left in a day: `(w rem 86400) div 3600` |
| `minutes` | the whole minutes of what is left in an hour: `(w rem 3600) div 60` |
| `seconds` | `m` modulo 60, with the fraction |
| `value` | the amount itself |

A fact about a property is a fact about the duration (D-194): the amounts whose component is what the fact leaves. The days and the value are in a row and leave **one** interval; the hours, minutes and seconds come back every day, hour or minute, and leave **a piece for each**. So `days` and `value` are exact on any set, and the others need a bounded one:

| Condition | `dd` when true | `dd` when not true |
| --- | --- | --- |
| `dd.days = 0` | `days and time duration in (-P1D..P1D)` | `days and time duration in [-max..-P1D], [P1D..max] \| Null` |
| `dd.days > 1` | `days and time duration in [P2D..max]` | `days and time duration in [-max..P2D) \| Null` |
| `dd.days < 0` | `days and time duration in [-max..-P1D]` | `days and time duration in (-P1D..max] \| Null` |
| `dd.value > 3600` | `days and time duration in (PT1H..max]` | `days and time duration in [-max..PT1H] \| Null` |
| `dd.days >= 1 and dd.hours = 0` | `days and time duration in [P1D..max]` | `days and time duration \| Null` |
| `dd.hours >= 18` | `days and time duration` | `days and time duration \| Null` |
| `dd.seconds = 30` | `days and time duration` | `days and time duration \| Null` |

`dd.days = 0` is symmetric around zero because the sign is put back. `dd.days >= 1 and dd.hours = 0` keeps the days and drops the hours: the hours would need a piece for each day of an unbounded set.

With allowed values the set is bounded and the components have pieces to keep (`dds` is in `[PT0S..P3D]`):

| Condition | `dds` when true | `dds` when not true |
| --- | --- | --- |
| `dds > @"PT1H"` | `days and time duration in (PT1H..P3D]` | `days and time duration in [PT0S..PT1H] \| Null` |
| `dds >= @"P1D" and dds < @"P2D"` | `days and time duration in [P1D..P2D)` | `days and time duration in [PT0S..P1D), [P2D..P3D] \| Null` |
| `dds.days = 1` | `days and time duration in [P1D..P2D)` | `days and time duration in [PT0S..P1D), [P2D..P3D] \| Null` |
| `dds.hours >= 18` | `days and time duration in [PT18H..P1D), [P1DT18H..P2D), [P2DT18H..P3D)` | `days and time duration in [PT0S..PT18H), [P1D..P1DT18H), [P2D..P2DT18H), P3D \| Null` |
| `dds.hours = 5` | `days and time duration in [PT5H..PT6H), [P1DT5H..P1DT6H), [P2DT5H..P2DT6H)` | `days and time duration in [PT0S..PT5H), [PT6H..P1DT5H), [P1DT6H..P2DT5H), [P2DT6H..P3D] \| Null` |
| `dds.days >= 1 and dds.hours < 6` | `days and time duration in [P1D..P1DT6H), [P2D..P2DT6H), P3D` | `days and time duration in [PT0S..P3D] \| Null` |
| `dds.minutes = 30` | `days and time duration in [PT30M..P3D]` | `days and time duration in [PT0S..P3D] \| Null` |

- A **piece for each day** is what `dds.hours >= 18` leaves, and the exact set is a union of three intervals. `P3D` on its own is the one amount of the last day that is not below the end.
- `dds.minutes = 30` has a piece for each *hour*, which is more than 16 for three days: the set is the **hull**, from the first half hour to the end, a superset.
- The second row of the table is the `and` of two comparisons of the value, which meet exactly.

## Arithmetic in a comparison

A days and time duration is added, subtracted, multiplied and divided by a number as a number is, so an operation in a comparison narrows the operand by the preimage ([number](number.md#operations-in-the-comparison)):

| Condition | `dd` when true | `dd` when not true |
| --- | --- | --- |
| `dd + @"PT1H" > @"PT3H"` | `days and time duration in (PT2H..max]` | `days and time duration in [-max..PT2H0.000000000000000000000000000005S] \| Null` |
| `dd + @"PT1H" = @"PT2H"` | `days and time duration = PT1H` | `days and time duration in [-max..PT1H), (PT1H..max] \| Null` |
| `dd - @"PT1H" >= @"PT0S"` | `days and time duration in [PT1H..max]` | `days and time duration in [-max..PT1H) \| Null` |
| `@"P1D" - dd > @"PT1H"` | `days and time duration in [-max..PT23H)` | `days and time duration in [PT23H..max] \| Null` |
| `dd * 2 < @"PT1H"` | `days and time duration in [-max..PT30M)` | `days and time duration in [-max..-PT4.999999999999999999999999999999999E+6144S], [PT30M..max] \| Null` |
| `dd / 2 > @"PT1H"` | `days and time duration in (PT2H..max]` | `days and time duration in [-max..PT2H0.000000000000000000000000000001S] \| Null` |
| `-dd < @"PT1H"` | `days and time duration in (-PT1H..max]` | `days and time duration in [-max..-PT1H] \| Null` |
| `dd * x > @"PT1H"` | `days and time duration in [-max..PT0S), (PT0S..max]` | `days and time duration \| Null` |

| Condition | `x` when true | `x` when not true |
| --- | --- | --- |
| `@"PT1H" * x > @"PT2H"` | `number in (2..max]` | `number in [-max..2], [2.777777777777777777777777777777777E+6141..max] \| Null` |
| `dd * x > @"PT1H"` | `number in [-max..0), (0..max]` | `number \| Null` |

The number that multiplies is narrowed too (`@"PT1H" * x > @"PT2H"` needs `x` above 2). `dd * x > @"PT1H"` cannot be true for a zero in either operand, so both lose it.

The `else` is read as it is for numbers ([number](number.md#operations-in-the-comparison)): the durations the comparison is `false` for, and those for which the operation is `null` (`Feel.Analysis.Failure`, the seconds being a number). A sum with a constant cannot be (`dd + @"PT1H" > …` has no more than the first), a product or a quotient can: `dd * 2 < @"PT1H"` is not true of a duration of more than half of the largest number of seconds, for which the product is `null`. A duration of 10^30 seconds or more is written as its seconds, in scientific notation (`PT4.999999999999999999999999999999999E+6144S`), and not as thousands of digits of days. A duration next to a duration or a number that is not known is `null` for some (and every) duration, and the `else` says nothing of it.

The types of the arithmetic itself are `Feel.Analysis.Inference`'s:

| Expression | Type | Warnings |
| --- | --- | --- |
| `dd + @"PT1H"` | `days and time duration \| Null` | — |
| `dds + @"PT1H"` | `days and time duration in [PT1H..P3DT1H] \| Null` | — |
| `dds * 2` | `days and time duration in [PT0S..P6D] \| Null` | — |
| `dd - dd` | `days and time duration = PT0S \| Null` | — |
| `dd / dd` | `number = 1 \| Null` | — |

Full analysis recognizes the repeated read in the last two rows (D-170, D-207). A non-null duration subtracts from itself to zero; it divides by itself to one unless it is zero, which gives null. The core tier keeps independent-operand types for repeated reads.

## Limits

- A set of more than **16 pieces** is replaced by the one interval that holds them all.
- A property of an unbounded set (`dd.hours`, `dd.minutes`, `dd.seconds`) says nothing: every value of the remainder is in a long enough interval (`hours` in a day, `minutes` in an hour).
- The amounts are as fine as a number goes, so the ends of a duration have up to 34 digits.
- Repeated addition still sums independent intervals. If a duration is either one or six seconds, `dd + dd` has a type containing seven seconds, although only two or twelve seconds can be returned.

See also: [years and months duration](years-and-months-duration.md), [date and time](date-and-time.md), [number](number.md).
