The times and dates and times that a time or a date and time plus or minus a duration can be (D-109).
The run (Feel.Runtime.Temporal) moves a date and time in two ways, and a time in one:
| The duration | The date and time it gives |
|---|---|
years and months duration | the months added to the date of the clock, the day cut to the length of the month, the time of the day and the zone kept; null when the year leaves the calendar (as for a date, Feel.Analysis.DateArithmetic) |
days and time duration | the seconds added to the instant: elapsed time, so the clock follows by the offset the zone has then (a zone id can have another offset); null when the clock leaves the calendar |
| The duration | The time it gives |
|---|---|
days and time duration | the seconds added to the second of the day, which wraps round: 23:00:00 plus two hours is 01:00:00; the zone is kept, and it is never null |
Of the three lines of a set (Feel.Type.Moment), the clock of the values with no zone moves with the clock and the
second, so it is worked out exactly: by months, the days of the clock as DateArithmetic does for a date with the
time of the day kept, and by seconds, as a number plus the seconds. A value with a zone is known by its instant and its
clock, and one of them follows from the move, and the other only within the largest offset of it:
| A value with a zone, plus | The line that is exact | The other |
|---|---|---|
| months | the clock | the instant, within 18 hours of it |
| seconds | the instant (a zone id moves by elapsed time as a fixed offset does), less the time the clock went back in the zone, if it did, which the run reads as the earlier instant (Feel.Type.Moment.overlap/1) | the clock, within 18 hours of it |
| seconds, for a time | both: the zone of a time has an offset that does not change with the day |
The fraction of a second is a line of the set (D-118), and a number of seconds that is not whole carries it over a
second: 10:00:00.7 plus PT0.5S is 10:00:01.2, and 10:00:00.2 plus it is 10:00:00.7. The seconds are added in
their whole part and their fraction, and the fractions of the value and of the number are added: a sum below a second
moves the second by the whole part and leaves the sum, and a sum of a second or more moves it by one more and leaves
the rest. So the second and the fraction of the result are exact where the fractions of the value are, and where they
are not (any, [0..1)) the second is that of the whole part or one more.
The result is null for a date and time exactly when the clock of a move is outside the calendar (for a value with a
zone, when it can be, since the clock is known to 18 hours), and never for a time.
The difference
Two times, two dates and times, or a date and a date and time, are subtracted (difference/4, D-109) as the run does
(Feel.Runtime.Temporal): the seconds between their clocks when neither has a zone, between their instants when
both have one, and null when one has a zone and the other has none. A date is taken as midnight UTC, so it has a zone.
The image is the second and the value has a fraction of it (a line of the set, D-118), so the seconds between two are
those between their images and the fraction of the first less that of the second: 10:00:00.9 less 09:00:00.1 is
3,600.8, and 10:00:00 less 09:00:00 is 3,600 exactly. Where the fractions are not known (any, [0..1)) it is a
second either way, and for a date, which has none, on the side of the fraction of the date and time. The run rounds
the seconds to the 34 digits of a number, so the ends are rounded outwards to them.
iex> alias Feel.Type.{Moment, NumberSet}
iex> {:ok, date_time} = Feel.Value.DateTime.parse("2021-01-31T10:00:00")
iex> {:ok, [clock]} = Moment.images(date_time)
iex> {set, false} = Feel.Analysis.MomentArithmetic.shift(:date_and_time, NumberSet.point(clock), :years_and_months_duration, NumberSet.point(Decimal.new(1)), :add)
iex> Feel.Type.Union.format([{:date_and_time, set}])
"date and time = 2021-02-28T10:00:00"
Summary
Functions
The seconds between a time, a date and time or a date and another of the kinds that the run subtracts, as the set of the
days and time durations they can be, and whether the result can be null (one has a zone and the other has none). It is
:error for kinds that are not subtracted.
The set of a time or a date and time plus (:add) or minus (:subtract) a duration of a set, and whether the result
can be null. It is :error if the duration has no value that the move takes (a set with no whole month).
Functions
@spec difference(atom(), Feel.Type.NumberSet.t(), atom(), Feel.Type.NumberSet.t()) :: {Feel.Type.NumberSet.t(), boolean()} | :error
The seconds between a time, a date and time or a date and another of the kinds that the run subtracts, as the set of the
days and time durations they can be, and whether the result can be null (one has a zone and the other has none). It is
:error for kinds that are not subtracted.
iex> alias Feel.Type.{Moment, NumberSet}
iex> {:ok, later} = Feel.Value.Time.parse("10:00:00")
iex> {:ok, earlier} = Feel.Value.Time.parse("09:00:00")
iex> {:ok, [a]} = Moment.images(later)
iex> {:ok, [b]} = Moment.images(earlier)
iex> {seconds, false} = Feel.Analysis.MomentArithmetic.difference(:time, NumberSet.point(a), :time, NumberSet.point(b))
iex> NumberSet.format(seconds)
"[3599..3601]"
@spec shift( Feel.Type.Moment.kind(), Feel.Type.NumberSet.t(), :years_and_months_duration | :days_and_time_duration, Feel.Type.NumberSet.t(), :add | :subtract ) :: {Feel.Type.NumberSet.t(), boolean()} | :error
The set of a time or a date and time plus (:add) or minus (:subtract) a duration of a set, and whether the result
can be null. It is :error if the duration has no value that the move takes (a set with no whole month).