github ↗
docs menu

Module Expr.Temporal

Temporal values.

A datetime column holds instants or wall clocks (Instants and wall clocks), and a zone is an argument only of the conversions wall and localize. field, and floor or offset by a calendar step, read a wall clock as it is; on an instant they are a problem that names wall.

A zone's clock can repeat or skip a reading. The readings of a fold occur twice, on the offset before the change and then on the one after, and those of a gap never occur. A policy resolves such a reading:

  • `Earlier is the earlier instant, a fold's first occurrence or a gap's reading moved back by the gap's length;
  • `Later is the later instant, a fold's second occurrence or a gap's reading moved forward by the gap's length;
  • `Null is null, and `Fail a data error naming the reading.
#val add : ('a, 's) t -> (Time.span, 's) t -> ('a, 's) t

add a d is a advanced by d, of a's type: a datetime, a duration or a clock, d being a duration of a's unit or a coarser one, or a date, d being whole days. A literal d that is not whole days is a problem, and another a data error. A result out of range, or a clock outside its day, is a data error.

#val diff : ('a, 's) t -> ('a, 's) t -> (Time.span, 's) t

diff a b is the span from b to a: a duration of their common unit for datetimes, durations and clocks, which meet as Type.common says, and duration[s] for dates.

#val div : (Time.span, 's) t -> (Time.span, 's) t -> (float, 's) t

div a b is how many of b fit in a, as float64, for example div (diff ts signup) (span (Time.Span.days 1)). Both operands are durations, each converted to float64 and the coarser scaled to the finer's unit, so a quotient of values that float64 holds exactly rounds once. A zero b gives an infinity or NaN as IEEE 754 divides them. A clock is a problem; cast it to a duration first. It is null where an operand is.

#type field = [
  1. #| `Year
  2. #| `Month
  3. #| `Day
  4. #| `Hour
  5. #| `Minute
  6. #| `Second
  7. #| `Nanosecond
  8. #| `Weekday
  9. #| `Yearday
]

The type for calendar fields:

  • `Year, astronomical: year 0 is 1 BC;
  • `Month, 1 to 12, and `Day, the day of the month, 1 to 31;
  • `Hour, 0 to 23, `Minute and `Second, 0 to 59;
  • `Nanosecond, the nanosecond within the second;
  • `Weekday, the ISO day of the week, 1 for Monday to 7;
  • `Yearday, the day of the year, 1 to 366.
#val field : field -> ('a, 's) t -> (int, 's) t

field f a is the field f of a, as int64: field `Year orderdate. a is a date, a clock or a wall clock. A date has no time-of-day field and a clock no calendar field: asking for one is a problem.

#val floor : Time.step -> ('a, 's) t -> ('a, 's) t

floor step a is the first value of the period of step that holds a, a date or a datetime. Periods are counted from 1970-01-01 00:00, and weeks from Monday 1970-01-05. A date floors by calendar steps only, a wall clock by either, and an instant by exact steps; an exact step is whole ticks of the datetime's unit. Its type is a's.

Raises Invalid_argument if step is not positive.

#val offset : Time.step -> ('a, 's) t -> ('a, 's) t

offset step a is a, a date or a datetime, moved by step: an exact step adds ticks, and a calendar step moves the calendar date of a wall clock; a day of the month past the month's end becomes its last day. A date moves by calendar steps only, a wall clock by either, and an instant by exact steps of whole ticks of its unit. Its type is a's.

#val wall : Tz.zone -> (Time.instant, 's) t -> (Time.wall, 's) t

wall z a is the reading of z's wall clock at the instant a, in a's unit: a plus the offset of z at a (Tz.offset_s). A result out of range is a data error.

#type policy = [
  1. #| `Earlier
  2. #| `Later
  3. #| `Null
  4. #| `Fail
]

The type for what localize and localize_ordered do with a reading that a zone repeats or skips, as the section's preamble describes.

#val localize : Tz.zone -> ambiguous:policy -> gap:policy -> (Time.wall, 's) t -> (Time.instant, 's) t

localize z ~ambiguous ~gap a is the instant at which z's wall clock reads a, in a's unit: a - o for the offset o of Tz.local's Unique o. A reading that z repeats follows ambiguous, and one it skips gap. On a gap, `Later is a - before and `Earlier is a - after in Tz.local's terms. localize z ~ambiguous ~gap (wall z a) is a where z repeats no reading. An instant out of range is a data error.

#val localize_ordered : Tz.zone -> ambiguous:policy -> gap:policy -> (Time.wall, row) t -> (Time.instant, row) t

localize_ordered z ~ambiguous ~gap a is localize where the order of each frame's rows (Frames), which must be time order, decides the pass of a reading that z repeats. The rows of one fold, consecutive apart from nulls, read as the fold's first pass up to the first row strictly below its predecessor, and as the second from it. Two equal rows that are a fold's only rows read one per pass when the row on each side lies the fold's length from them, as a logger of that cadence writes them. Other rows of a fold follow ambiguous. Order finds the pass only at a cadence at or below the fold's length, and at that cadence a duplicate whose other pass is lost reads as the two passes. Nulls and rows moved by gap are not a previous row. An equal instant is allowed. A row not moved by gap whose instant is before the previous row's is a data error, as is an instant out of range.

#val parse : string -> 'a Type.t -> (string, 's) t -> ('a, 's) t

parse fmt ty a reads the text a in the format fmt as a value of ty, a date, datetime or clock type. fmt holds the directives %Y (the year), %m, %d, %H, %M, %S (two digits each), %f (one to nine digits of a fraction of a second), %z (Z or a ±hh:mm offset) and %%; other characters match themselves. A year is four digits, or a sign and at least four digits, as Time.Date.pp writes it. A field that fmt leaves out is that of 1970-01-01 00:00:00; a date reads the day alone, and a clock the time of day. An instant needs %z in fmt, and a wall clock takes none. Text that does not match, and a value that ty does not hold, are data errors.

Raises Invalid_argument if fmt holds another directive.

#val format : string -> ('a, 's) t -> (string, 's) t

format fmt a writes a, a date, datetime or clock, in the format fmt, as parse reads it: a datetime as its clock reads, a clock on 1970-01-01; %f writes nine digits and %z writes Z. %z needs an instant.

Raises Invalid_argument as parse does.