# Temporal Types: Generic Operations (Part 1)

## Introduction

We present next the functions and operators for temporal types. These functions and operators are polymorphic, that is, their arguments may be of several types, and the result type may depend on the type of the arguments. To express this, we use the following notation:

- `time` represents any time type, that is, `timestamptz`, `tstzspan`, `tstzset`, or `tstzspanset`,

- `ttype` represents any temporal type,

- `tdisc` represents any temporal type with a discrete base type, that is, `tbool`, `tint`, or `ttext`,

- `tcont` represents any temporal type with a continuous base type, that is, `tfloat`, `tgeompoint`, or `tgeogpoint`,

- `torder` represents any temporal type whose base type has a total order defined, that is, `tint`, `tfloat`, or `ttext`,

- `talpha` represents any temporal alphanumeric type, such as, `tint` or `ttext`,

- `tnumber` represents any temporal number type, that is, `tint` or `tfloat`,

- `tpoint` represents a temporal point type, that is, `tgeompoint` or `tgeogpoint`,

- `ttypeInst` represents any temporal type with instant subtype,

- `ttypeDiscSeq` represents any temporal type with sequence subtype and discrete interpolation,

- `ttypeContSeq` represents any temporal type with sequence subtype and continuous interpolation,

- `ttypeSeqSet` represents any temporal type with sequence set subtype,

- `base` represents any base type of a temporal type, that is, `boolean`, `integer`, `float`, `text`, `geometry`, or `geography`,

- `values` represents any set of values of a base type of a temporal type, for example, `integer`, `intset`, `intspan`, and `intspanset` for the base type `integer`

- `number` represents any number base type, that is, `integer` or `float`,

- `numspan` represents any number span type, that is, either `intspan` or `floatspan`,

- `geo` represents the types `geometry` or `geography`,

- `geompoint` represents the type `geometry` restricted to a point.

- `point` represents the types `geometry` or `geography` restricted to a point.

- `lines` represents the types `geometry` or `geography` restricted to a (multi)line.

- `type[]` represents an array of `type`.

- `<type>` in the name of a function represents the functions obtained by replacing `<type>` by a specific `type`. For example, `tintDiscSeq` or `tfloatDiscSeq` are represented by `ttypeDiscSeq`.

A common way to generalize the traditional operations to the temporal types is to apply the operation at each instant, which yields a temporal value as result. In that case, the operation is only defined on the intersection of the emporal extents of the operands; if the temporal extents are disjoint, then the result is null. For example, the temporal comparison operators, such as `#<`, test whether the values taken by their operands at each instant satisfy the condition and return a temporal Boolean. Examples of the various generalizations of the operators are given next.

    -- Temporal comparison
    SELECT tfloat '[2@2001-01-01, 2@2001-01-03)' #< tfloat '[1@2001-01-01, 3@2001-01-03)';
    -- {[f@2001-01-01, f@2001-01-02], (t@2001-01-02, t@2001-01-03)}
    SELECT tfloat '[1@2001-01-01, 3@2001-01-03)' #< tfloat '[3@2001-01-03, 1@2001-01-05)';
    -- NULL

    -- Temporal addition
    SELECT tint '[1@2001-01-01, 1@2001-01-03)' + tint '[2@2001-01-02, 2@2001-01-05)';
    -- [3@2001-01-02, 3@2001-01-03)

    -- Temporal intersects
    SELECT tIntersects(tgeompoint '[Point(0 1)@2001-01-01, Point(3 1)@2001-01-04)',
      geometry 'Polygon((1 0,1 2,2 2,2 0,1 0))');
    -- {[f@2001-01-01, t@2001-01-02, t@2001-01-03], (f@2001-01-03, f@2001-01-04]}

    -- Temporal distance
    SELECT tgeompoint '[Point(0 0)@2001-01-01 08:00:00, Point(0 1)@2001-01-03 08:10:00)' <->
      tgeompoint '[Point(0 0)@2001-01-02 08:05:00, Point(1 1)@2001-01-05 08:15:00)';
    -- [0.5@2001-01-02 08:05:00+00, 0.745184033794557@2001-01-03 08:10:00+00)

Another common requirement is to determine whether the operands ever or always satisfy a condition with respect to an operation. These can be obtained by applying the ever or always comparison operators. These operators are denoted by prefixing the traditional comparison operators with, respectively, `?` (ever) and `%` (always). Examples of ever and always comparison operators are given next.

    -- Does the operands ever intersect?
    SELECT eIntersects(tgeompoint '[Point(0 1)@2001-01-01, Point(3 1)@2001-01-04)',
      geometry 'Polygon((1 0,1 2,2 2,2 0,1 0))') ?= true;
    -- true

    -- Does the operands always intersect?
    SELECT aIntersects(tgeompoint '[Point(0 1)@2001-01-01, Point(3 1)@2001-01-04)',
      geometry 'Polygon((0 0,0 2,4 2,4 0,0 0))') %= true;
    -- true

    -- Is the left operand ever less than the right one ?
    SELECT (tfloat '[1@2001-01-01, 3@2001-01-03)' #<
      tfloat '[3@2001-01-01, 1@2001-01-03)') ?= true;
    -- true

    -- Is the left operand always less than the right one ?
    SELECT (tfloat '[1@2001-01-01, 3@2001-01-03)' #<
      tfloat '[2@2001-01-01, 4@2001-01-03)') %= true;
    -- true

For example, the `eIntersects` function determines whether there is an instant at which the two arguments spatially intersect.

We describe next the functions and operators for temporal types. For conciseness, in the examples we mostly use sequences composed of two instants.

## Input and Output

MobilityDB generalizes Open Geospatial Consortium's Well-Known Text (WKT), Well-Known Binary (WKB), and Moving Features JSON (MF-JSON) input and output format for all temporal types. We start by describing the WKT format.

An instant value is a couple of the form `v@t`, where `v` is a value of the base type and `t` is a `timestamptz` value. The temporal extent of an instant value is a single timestamp. Examples of instant values are as follows:

    SELECT tbool 'true@2001-01-01 08:00:00';
    SELECT tint '1@2001-01-01 08:00:00';
    SELECT tfloat '1.5@2001-01-01 08:00:00';
    SELECT ttext 'AAA@2001-01-01 08:00:00';
    SELECT tgeompoint 'Point(0 0)@2017-01-01 08:00:05';
    SELECT tgeogpoint 'Point(0 0)@2017-01-01 08:00:05';

A sequence value is a set of values `v1@t1,...,vn@tn` delimited by lower and upper bounds, which can be inclusive (represented by ‘`[`’ and ‘`]`’) or exclusive (represented by ‘`(`’ and ‘`)`’). A sequence value composed of a single couple `v@t` is called an instantaneous sequence. Sequence values have an associated interpolation function which may be discrete, linear, or step. By definition, the lower and upper bounds of an instantaneous sequence or of a sequence value with discrete interpolation are inclusive. The temporal extent of a sequence value with discrete interpolation is a timestamp set. Examples of sequence values with discrete interpolation are as follows.

    SELECT tbool '{true@2001-01-01 08:00:00, false@2001-01-03 08:00:00}';
    SELECT tint '{1@2001-01-01 08:00:00, 2@2001-01-03 08:00:00}';
    SELECT tint '{1@2001-01-01 08:00:00}'; -- Instantaneous sequence
    SELECT tfloat '{1.0@2001-01-01 08:00:00, 2.0@2001-01-03 08:00:00}';
    SELECT ttext '{AAA@2001-01-01 08:00:00, BBB@2001-01-03 08:00:00}';
    SELECT tgeompoint '{Point(0 0)@2017-01-01 08:00:00, Point(0 1)@2017-01-02 08:05:00}';
    SELECT tgeogpoint '{Point(0 0)@2017-01-01 08:00:00, Point(0 1)@2017-01-02 08:05:00}';

The temporal extent of a sequence value with linear or step interpolation is a period defined by the first and last instants as well as the lower and upper bounds. Examples of sequence values with linear interpolation are as follows:

    SELECT tbool '[true@2001-01-01 08:00:00, true@2001-01-03 08:00:00]';
    SELECT tint '[1@2001-01-01 08:00:00, 1@2001-01-03 08:00:00]';
    SELECT tfloat '[2.5@2001-01-01 08:00:00, 3@2001-01-03 08:00:00, 1@2001-01-04 08:00:00]';
    SELECT tfloat '[1.5@2001-01-01 08:00:00]'; -- Instantaneous sequence
    SELECT ttext '[BBB@2001-01-01 08:00:00, BBB@2001-01-03 08:00:00]';
    SELECT tgeompoint '[Point(0 0)@2017-01-01 08:00:00, Point(0 0)@2017-01-01 08:05:00)';
    SELECT tgeogpoint '[Point(0 0)@2017-01-01 08:00:00, Point(0 1)@2017-01-01 08:05:00,
      Point(0 0)@2017-01-01 08:10:00)';

Sequence values whose base type is continuous may specify that the interpolation is step with the prefix `Interp=Step`. If this is not specified, it is supposed that the interpolation is linear by default. Example of sequence values with step interpolation are given next:

    SELECT tfloat 'Interp=Step;[2.5@2001-01-01 08:00:00, 3@2001-01-01 08:10:00]';
    SELECT tgeompoint 'Interp=Step;[Point(0 0)@2017-01-01 08:00:00,
      Point(1 1)@2017-01-01 08:05:00, Point(1 1)@2017-01-01 08:10:00)';
    SELECT tgeompoint 'Interp=Step;[Point(0 0)@2017-01-01 08:00:00,
     Point(1 1)@2017-01-01 08:05:00, Point(0 0)@2017-01-01 08:10:00)';
    ERROR:  Invalid end value for temporal sequence with step interpolation
    SELECT tgeogpoint 'Interp=Step;[Point(0 0)@2017-01-01 08:00:00,
      Point(1 1)@2017-01-01 08:10:00]';

The last two instants of a sequence value with discrete interpolation and exclusive upper bound must have the same base value, as shown in the second and third examples above.

A sequence set value is a set `{v1,...,vn}` where every `vi` is a sequence value. The interpolation of sequence set values can only be linear or step, not discrete. All sequences composing a sequence set value must have the same interpolation. The temporal extent of a sequence set value is a set of periods. Examples of sequence set values with linear interpolation are as follows:

    SELECT tbool '{[false@2001-01-01 08:00:00, false@2001-01-03 08:00:00),
      [true@2001-01-03 08:00:00], (false@2001-01-04 08:00:00, false@2001-01-06 08:00:00]}';
    SELECT tint '{[1@2001-01-01 08:00:00, 1@2001-01-03 08:00:00),
      [2@2001-01-04 08:00:00, 3@2001-01-05 08:00:00, 3@2001-01-06 08:00:00]}';
    SELECT tfloat '{[1@2001-01-01 08:00:00, 2@2001-01-03 08:00:00, 2@2001-01-04 08:00:00,
      3@2001-01-06 08:00:00]}';
    SELECT ttext '{[AAA@2001-01-01 08:00:00, BBB@2001-01-03 08:00:00, BBB@2001-01-04 08:00:00),
      [CCC@2001-01-05 08:00:00, CCC@2001-01-06 08:00:00]}';
    SELECT tgeompoint '{[Point(0 0)@2017-01-01 08:00:00, Point(0 1)@2017-01-01 08:05:00),
      [Point(0 1)@2017-01-01 08:10:00, Point(1 1)@2017-01-01 08:15:00)}';
    SELECT tgeogpoint '{[Point(0 0)@2017-01-01 08:00:00, Point(0 1)@2017-01-01 08:05:00),
      [Point(0 1)@2017-01-01 08:10:00, Point(1 1)@2017-01-01 08:15:00)}';

Sequence set values whose base type is continuous may specify that the interpolation is step with the prefix `Interp=Step`. If this is not specified, it is supposed that the interpolation is linear by default. Example of sequence set values with step interpolation are given next:

    SELECT tfloat 'Interp=Step;{[1@2001-01-01 08:00:00, 2@2001-01-03 08:00:00,
      2@2001-01-04 08:00:00, 3@2001-01-06 08:00:00]}';
    SELECT tgeompoint 'Interp=Step;{[Point(0 0)@2017-01-01 08:00:00,
      Point(0 1)@2017-01-01 08:05:00], [Point(0 1)@2017-01-01 08:10:00,
      Point(0 1)@2017-01-01 08:15:00)}';
    SELECT tgeogpoint 'Interp=Step;{[Point(0 0)@2017-01-01 08:00:00,
      Point(0 1)@2017-01-01 08:05:00], [Point(0 1)@2017-01-01 08:10:00,
      Point(0 1)@2017-01-01 08:15:00)}';

For temporal points, it is possible to specify the spatial reference identifier (SRID) using the Extended Well-Known text (EWKT) representation as follows:

    SELECT tgeompoint 'SRID=5435;[Point(0 0)@2001-01-01,Point(0 1)@2001-01-02]'

All component geometries of a temporal point will then be of the given SRID. Furthermore, each component geometry can specify its SRID with the EWKT format as in the following example

    SELECT tgeompoint '[SRID=5435;Point(0 0)@2001-01-01,SRID=5435;Point(0 1)@2001-01-02]'

An error is raised if the component geometries are not all in the same SRID or if the SRID of a component geometry is different from the one of the temporal point, as shown below.

    SELECT tgeompoint '[SRID=5435;Point(0 0)@2001-01-01,SRID=4326;Point(0 1)@2001-01-02]';
    -- ERROR: Geometry SRID (4326) does not match temporal type SRID (5435)
    SELECT tgeompoint 'SRID=5435;[SRID=4326;Point(0 0)@2001-01-01,
      SRID=4326;Point(0 1)@2001-01-02]';
    -- ERROR: Geometry SRID (4326) does not match temporal type SRID (5435)

If not specified, the default SRID for temporal geometric points is 0 (unknown) and for temporal geographic points is 4326 (WGS 84). Temporal points with step interpolation may also specify the SRID, as shown next.

    SELECT tgeompoint 'SRID=5435,Interp=Step;[Point(0 0)@2001-01-01,
      Point(0 1)@2001-01-02]';
    SELECT tgeogpoint 'Interp=Step;[SRID=4326;Point(0 0)@2001-01-01,
      SRID=4326;Point(0 1)@2001-01-02]';

We give below the input and output functions in Well-Known Text (WKT), Well-Known Binary (WKB), and Moving Features JSON (MF-JSON) format for temporal alphanumeric types. The corresponding functions for temporal points are detailed in tpoint_inout. The default output format of all temporal alphanumeric types is the Well-Known Text format. The function `asText` given next enables to determine the output of temporal float values.

- Return the Well-Known Text (WKT) representation

  `asText(tfloat,maxdecdigits=15) → text`

  The `maxdecdigits` argument can be used to set the maximum number of decimal places in the output of floating point values (default 15).

      SELECT asText(tfloat '[10.55@2001-01-01, 25.55@2001-01-02]', 0);
      -- [11@2001-01-01, 26@2001-01-02]

- Return the Well-Known Binary (WKB) representation

  `asBinary(ttype,endian text='') → bytea`

  The result is encoded using either the little-endian (NDR) or the big-endian (XDR) encoding. If no encoding is specified, then the encoding of the machine is used.

      SELECT asBinary(tbool 'true@2001-01-01');
      -- \x011a000101009c57d3c11c0000
      SELECT asBinary(tint '1@2001-01-01', 'XDR');
      -- \x000023010000000100001cc1d3579c00
      SELECT asBinary(tfloat '1.5@2001-01-01');
      -- \x01210001000000000000f83f009c57d3c11c0000
      SELECT asBinary(ttext 'AAA@2001-01-01');
      -- \x01290001040000000000000041414100009c57d3c11c0000

- Return the Hexadecimal Well-Known Binary (WKB) representation as text

  `asHexWKB(ttype,endian text='') → text`

  The result is encoded using either the little-endian (NDR) or the big-endian (XDR) encoding. If no encoding is specified, then the encoding of the machine is used.

      SELECT asHexWKB(tbool 'true@2001-01-01');
      -- 011A000101009C57D3C11C0000
      SELECT asHexWKB(tint '1@2001-01-01', 'XDR');
      -- 000023010000000100001CC1D3579C00
      SELECT asHexWKB(tfloat '1.5@2001-01-01');
      -- 01210001000000000000F83F009C57D3C11C0000
      SELECT asHexWKB(ttext 'AAA@2001-01-01');
      -- 01290001040000000000000041414100009C57D3C11C0000

- Return the Moving Features JSON (MF-JSON) representation

  `asMFJSON(ttype,options=0,flags=0,maxdecdigits=15) → bytea`

  The `options` argument can be used to add a bounding box in the MFJSON output:

  - 0: means no option (default value)

  - 1: MFJSON BBOX

  The `flags` argument can be used to customize the JSON output, for example, to produce an easy-to-read (for human readers) JSON output. Refer to the documentation of the `json-c` library for the possible values. Typical values are as follows:

  - 0: means no option (default value)

  - 1: JSON_C_TO_STRING_SPACED

  - 2: JSON_C_TO_STRING_PRETTY

  The `maxdecdigits` argument can be used to set the maximum number of decimal places in the output of floating point values (default 15).

      SELECT asMFJSON(tbool 't@2001-01-01 18:00:00', 1);
      /* {"type":"MovingBoolean","period":{"begin":"2001-01-01T18:00:00+01",
        "end":"2001-01-01T18:00:00+01","lowerInc":true,"upperInc":true},
        "values":[true],"datetimes":["2001-01-01T18:00:00+01"],"interpolation":"None"} */
      SELECT asMFJSON(tint '{10@2001-01-01 18:00:00, 25@2001-01-01 18:10:00}', 1);
      /* {"type":"MovingInteger","bbox":[10,25],"period":{"begin":"2001-01-01T18:00:00+01",
         "end":"2001-01-01T18:10:00+01"},"values":[10,25],"datetimes":["2001-01-01T18:00:00+01",
         "2001-01-01T18:10:00+01"],"lowerInc":true,"upperInc":true,
         "interpolation":"Discrete"} */
      SELECT asMFJSON(tfloat '[10.5@2001-01-01 18:00:00+02, 25.5@2001-01-01 18:10:00+02]');
      /* {"type":"MovingFloat","values":[10.5,25.5],"datetimes":["2001-01-01T17:00:00+01",
        "2001-01-01T17:10:00+01"],"lowerInc":true,"upperInc":true,"interpolation":"Linear"} */
      SELECT asMFJSON(ttext '{[walking@2001-01-01 18:00:00+02,
        driving@2001-01-01 18:10:00+02]}');
      /* {"type":"MovingText","sequences":[{"values":["walking","driving"],
        "datetimes":["2001-01-01T17:00:00+01","2001-01-01T17:10:00+01"],
        "lowerInc":true,"upperInc":true}],"interpolation":"Step"} */

- Input a temporal value from its Well-Known Binary (WKB) representation

  `ttypeFromBinary(bytea) → ttype`

  There is one function per temporal type, the name of the function has as prefix the name of the type, which is `tbool` or `tint` in the examples below.

      SELECT tboolFromBinary('\x011a000101009c57d3c11c0000');
      -- t@2001-01-01
      SELECT tintFromBinary('\x000023010000000100001cc1d3579c00');
      -- 1@2001-01-01
      SELECT tfloatFromBinary('\x01210001000000000000f83f009c57d3c11c0000');
      -- 1.5@2001-01-01
      SELECT ttextFromBinary('\x01290001040000000000000041414100009c57d3c11c0000');
      -- "AAA"@2001-01-01

- Input a temporal value from its Hexadecimal Extended Well-Known Binary (HexEWKB) representation

  `ttypeFromHexWKB(text) → ttype`

  There is one function per temporal type, the name of the function has as prefix the name of the type, which is `tbool` or `tint` in the examples below.

      SELECT tboolFromHexWKB('011A000101009C57D3C11C0000');
      -- t@2001-01-01
      SELECT tintFromHexWKB('000023010000000100001CC1D3579C00');
      -- 1@2001-01-01
      SELECT tfloatFromHexWKB('01210001000000000000F83F009C57D3C11C0000');
      -- 1.5@2001-01-01
      SELECT ttextFromHexWKB('01290001040000000000000041414100009C57D3C11C0000');
      -- "AAA"@2001-01-01

- Input a temporal value from its Moving Features JSON (MF-JSON) representation

  `ttypeFromMFJSON(bytea) → ttype`

  There is one function per temporal type, the name of the function has as prefix the name of the type, which is `tbool` or `tint` in the examples below.

      SELECT tboolFromMFJSON(text
        '{"type":"MovingBoolean","period":{"begin":"2001-01-01T18:00:00+01",
        "end":"2001-01-01T18:00:00+01","lowerInc":true,"upperInc":true},
        "values":[true],"datetimes":["2001-01-01T18:00:00+01"],"interpolation":"None"}');
      -- t@2001-01-01 18:00:00
      SELECT tintFromMFJSON(text
        '{"type":"MovingInteger","bbox":[10,25],"period":{"begin":"2001-01-01T18:00:00+01",
         "end":"2001-01-01T18:10:00+01"},"values":[10,25],"datetimes":["2001-01-01T18:00:00+01",
         "2001-01-01T18:10:00+01"],"lowerInc":true,"upperInc":true,
         "interpolation":"Discrete"}');
      -- {10@2001-01-01 18:00:00, 25@2001-01-01 18:10:00}
      SELECT tfloatFromMFJSON(text
        '{"type":"MovingFloat","values":[10.5,25.5],"datetimes":["2001-01-01T17:00:00+01",
         "2001-01-01T17:10:00+01"],"lowerInc":true,"upperInc":true,
         "interpolation":"Linear"}');
      -- [10.5@2001-01-01 18:00:00, 25.5@2001-01-01 18:10:00]'
      SELECT ttextFromMFJSON(text
        '{"type":"MovingText","sequences":[{"values":["walking","driving"],
        "datetimes":["2001-01-01T17:00:00+01","2001-01-01T17:10:00+01"],
        "lowerInc":true,"upperInc":true}],"interpolation":"Step"}');
      -- {["walking"@2001-01-01 18:00:00, "driving"@2001-01-01 18:10:00]}');

## Constructors

We give next the constructor functions for the various subtypes. Using the constructor function is frequently more convenient than writing a literal constant.

- Constructors for temporal types having a constant value

  These contructors have two arguments, a base type and a time value, where the latter is a `timestamptz`, a `tstzset`, a `tstzspan`, or a `tstzspanset` value for constructing, respectively, an instant, a sequence with discrete interpolation, a sequence with linear or step interpolation, or a sequence set value. The functions for sequence or sequence set values with continuous base type have an optional third argument stating whether the resulting temporal value has linear or step interpolation. Linear interpolation is assumed by default if the argument is not specified.

  `ttype(base,timestamptz) → ttypeInst`

  `ttype(base,tstzset) → ttypeDiscSeq`

  `ttype(base,tstzspan,interp='linear') → ttypeContSeq`

  `ttype(base,tstzspanset,interp='linear') → ttypeSeqSet`

      SELECT tbool(true, timestamptz '2001-01-01');
      SELECT tint(1, timestamptz '2001-01-01');
      SELECT tfloat(1.5, tstzset '{2001-01-01, 2001-01-02}');
      SELECT ttext('AAA', tstzset '{2001-01-01, 2001-01-02}');
      SELECT tfloat(1.5, tstzspan '[2001-01-01, 2001-01-02]');
      SELECT tfloat(1.5, tstzspan '[2001-01-01, 2001-01-02]', 'step');
      SELECT tgeompoint('Point(0 0)', tstzspan '[2001-01-01, 2001-01-02]');
      SELECT tgeogpoint('SRID=7844;Point(0 0)', tstzspanset '{[2001-01-01, 2001-01-02],
        [2001-01-03, 2001-01-04]}', 'step');

- Constructors for temporal types of sequence subtype

  These contructors have a first mandatory argument, which is an array of values of the corresponding instant values and additional optional arguments. The second argument states the interpolation. If the argument is not given, it is by default step for discrete base types such as integer, and linear for continuous base types such as float. An error is raised when linear interpolation is stated for temporal values with discrete base types. For continuous sequences, the third and fourth arguments are Boolean values stating, respectively, whether the left and right bounds are inclusive or exclusive. These arguments are assumed to be true by default if they are not specified.

  `ttypeSeq(ttypeInst[],interp={'step','linear'},leftInc bool=true,`

  `rightInc bool=true) → ttypeSeq`

      SELECT tboolSeq(ARRAY[tbool 'true@2001-01-01 08:00:00','false@2001-01-01 08:05:00'],
        'discrete');
      SELECT tintSeq(ARRAY[tint '1@2001-01-01 08:00:00', '2@2001-01-01 08:05:00']);
      SELECT tintSeq(ARRAY[tint '1@2001-01-01 08:00:00', '2@2001-01-01 08:05:00'], 'linear');
      -- ERROR:  The temporal type cannot have linear interpolation
      SELECT tfloatSeq(ARRAY[tfloat '1.0@2001-01-01 08:00:00', '2.0@2001-01-01 08:05:00'],
        'step', false, true);
      SELECT ttextSeq(ARRAY[ttext 'AAA@2001-01-01 08:00:00', 'BBB@2001-01-01 08:05:00']);
      SELECT tgeompointSeq(ARRAY[tgeompoint 'Point(0 0)@2001-01-01 08:00:00',
        'Point(0 1)@2001-01-01 08:05:00', 'Point(1 1)@2001-01-01 08:10:00'], 'discrete');
      SELECT tgeogpointSeq(ARRAY[tgeogpoint 'Point(1 1)@2001-01-01 08:00:00',
        'Point(2 2)@2001-01-01 08:05:00']);

- Constructors for temporal types of sequence set subtype

  `ttypeSeqSet(ttypeContSeq[]) → ttypeSeqSet`

  `ttypeSeqSetGaps(ttypeInst[],maxt=NULL,maxdist=NULL,interp='linear') → ttypeSeqSet`

  A first set of contructors have a single argument, which is an array of values of the corresponding sequence values. The interpolation of the resulting temporal value depends on the interpolation of the composing sequences. An error is raised if the sequences composing the array have different interpolation.

      SELECT tboolSeqSet(ARRAY[tbool '[false@2001-01-01 08:00:00, false@2001-01-01 08:05:00)',
        '[true@2001-01-01 08:05:00]','(false@2001-01-01 08:05:00, false@2001-01-01 08:10:00)']);
      SELECT tintSeqSet(ARRAY[tint '[1@2001-01-01 08:00:00, 2@2001-01-01 08:05:00,
        2@2001-01-01 08:10:00, 2@2001-01-01 08:15:00)']);
      SELECT tfloatSeqSet(ARRAY[tfloat '[1.0@2001-01-01 08:00:00, 2.0@2001-01-01 08:05:00,
        2.0@2001-01-01 08:10:00]', '[2.0@2001-01-01 08:15:00, 3.0@2001-01-01 08:20:00)']);
      SELECT tfloatSeqSet(ARRAY[tfloat 'Interp=Step;[1.0@2001-01-01 08:00:00,
        2.0@2001-01-01 08:05:00, 2.0@2001-01-01 08:10:00]',
        'Interp=Step;[3.0@2001-01-01 08:15:00, 3.0@2001-01-01 08:20:00)']);
      SELECT ttextSeqSet(ARRAY[ttext '[AAA@2001-01-01 08:00:00, AAA@2001-01-01 08:05:00)',
        '[BBB@2001-01-01 08:10:00, BBB@2001-01-01 08:15:00)']);
      SELECT tgeompointSeqSet(ARRAY[tgeompoint '[Point(0 0)@2001-01-01 08:00:00,
        Point(0 1)@2001-01-01 08:05:00, Point(0 1)@2001-01-01 08:10:00)',
        '[Point(0 1)@2001-01-01 08:15:00, Point(0 0)@2001-01-01 08:20:00)']);
      SELECT tgeogpointSeqSet(ARRAY[tgeogpoint
        'Interp=Step;[Point(0 0)@2001-01-01 08:00:00, Point(0 0)@2001-01-01 08:05:00)',
        'Interp=Step;[Point(1 1)@2001-01-01 08:10:00, Point(1 1)@2001-01-01 08:15:00)']);
      SELECT tfloatSeqSet(ARRAY[tfloat 'Interp=Step;[1.0@2001-01-01 08:00:00,
        2.0@2001-01-01 08:05:00, 2.0@2001-01-01 08:10:00]',
        '[3.0@2001-01-01 08:15:00, 3.0@2001-01-01 08:20:00)']);
      -- ERROR:  The temporal values must have the same interpolation

  Another set of constructors for sequence set values have as first argument an array of the corresponding instant values, and two optional arguments stating a maximum time interval and a maximum distance such that a gap is introduced between sequences of the result whenever two consecutive input instants have a time gap or a distance greater than these values. For temporal points, the distance is specified in units of the coordinate system. When none of the gap arguments are given, the resulting value will be a singleton sequence set. In addition, when the base type is continuous, an additional last argument states whether the interpolation is step or linear. It this argument is not specified it is assumed to be linear by default.

  The parameters of the function depend on the temporal type. For example, the interpolation parameter is not allowed for temporal types with discrete subtype such as `tint`. Similarly, the parameter `maxdist` is not allowed for scalar types such as `ttext` that do not have a standard distance function.

      SELECT tintSeqSetGaps(ARRAY[tint '1@2001-01-01', '3@2001-01-02', '4@2001-01-03',
        '5@2001-01-05']);
      -- {[1@2001-01-01, 3@2001-01-02, 4@2001-01-03, 5@2001-01-05]}
      SELECT tintSeqSetGaps(ARRAY[tint '1@2001-01-01', '3@2001-01-02', '4@2001-01-03',
        '5@2001-01-05'], '1 day', 1);
      -- {[1@2001-01-01], [3@2001-01-02, 4@2001-01-03], [5@2001-01-05]}
      SELECT ttextSeqSetGaps(ARRAY[ttext 'AA@2001-01-01', 'BB@2001-01-02', 'AA@2001-01-03',
        'CC@2001-01-05'], '1 day');
      -- {["AA"@2001-01-01, "BB"@2001-01-02, "AA"@2001-01-03], ["CC"@2001-01-05]}
      SELECT asText(tgeompointSeqSetGaps(ARRAY[tgeompoint 'Point(1 1)@2001-01-01',
        'Point(2 2)@2001-01-02', 'Point(3 2)@2001-01-03', 'Point(3 2)@2001-01-05'],
        '1 day', 1, 'step'));
      /* Interp=Step;{[POINT(1 1)@2001-01-01], [POINT(2 2)@2001-01-02, POINT(3 2)@2001-01-03],
         [POINT(3 2)@2001-01-05]} */

## Conversions

A temporal value can be converted into a compatible type using the notation `CAST(ttype1 AS ttype2)` or `ttype1::ttype2`.

- Convert a temporal value to a bounding box

  `ttype::tstzspan`

  `tnumber::{numspan,tbox}`

  `tpoint::stbox`

      SELECT tint '[1@2001-01-01, 2@2001-01-03]'::tstzspan;
      -- [2001-01-01, 2001-01-03]
      SELECT ttext '(A@2001-01-01, B@2001-01-03, C@2001-01-05]'::tstzspan;
      -- (2001-01-01, 2001-01-05]
      SELECT tgeompoint '[Point(1 1)@2001-01-01, Point(3 3)@2001-01-03]'::tstzspan;
      -- [2001-01-01, 2001-01-03]

      SELECT tint '[1@2001-01-01, 2@2001-01-03]'::intspan;
      -- [1, 3)
      SELECT tfloat '(1@2001-01-01, 3@2001-01-03, 2@2001-01-05]'::floatspan;
      -- (1, 3]
      SELECT tfloat 'Interp=Step;(1@2001-01-01, 3@2001-01-03, 2@2001-01-05]'::floatspan;
      -- [1, 3]

      SELECT tint '[1@2001-01-01, 2@2001-01-03]'::tbox;
      -- TBOXINT XT((1,2),[2001-01-01,2001-01-03])
      SELECT tfloat '(1@2001-01-01, 3@2001-01-03, 2@2001-01-05]'::tbox;
      -- TBOXFLOAT XT((1,3),[2001-01-01,2001-01-05])
      SELECT tgeompoint '[Point(1 1)@2001-01-01, Point(3 3)@2001-01-03]'::stbox;
      -- STBOX XT(((1,1),(3,3)),[2001-01-01, 2001-01-03])
      SELECT tgeogpoint '[Point(1 1)@2001-01-01, Point(3 3)@2001-01-03]'::stbox;
      -- SRID=4326;GEODSTBOX XT(((1,1),(3,3)),[2001-01-01, 2001-01-03 00:00:00+01])
      SELECT tgeogpoint '[Point(1 1 1)@2001-01-01, Point(3 3 3)@2001-01-03]'::stbox;
      -- SRID=4326;GEODSTBOX ZT(((1,1,1),(3,3,3)),[2001-01-01, 2001-01-03])

- Convert between a temporal integer and a temporal float

  `tint::tfloat`

  `tfloat::tint`

      SELECT tint '[1@2001-01-01, 2@2001-01-03]'::tfloat;
      -- Interp=Step;[1@2001-01-01, 2@2001-01-03]
      SELECT tint '[1@2001-01-01, 2@2001-01-03, 3@2001-01-05]'::tfloat;
      -- Interp=Step;[1@2001-01-01, 2@2001-01-03, 3@2001-01-05]
      SELECT tfloat 'Interp=Step;[1.5@2001-01-01, 2.5@2001-01-03]'::tint;
      -- [1@2001-01-01, 2@2001-01-03]
      SELECT tfloat '[1.5@2001-01-01, 2.5@2001-01-03]'::tint;
      -- ERROR:  Cannot cast temporal float with linear interpolation to temporal integer

- Convert a temporal geometry point to a temporal geography point

  `tgeompoint::tgeogpoint`

  `tgeogpoint::tgeompoint`

      SELECT asText((tgeompoint '[Point(0 0)@2001-01-01, Point(0 1)@2001-01-02)')::tgeogpoint);
      -- {[POINT(0 0)@2001-01-01, POINT(0 1)@2001-01-02)}
      SELECT asText((tgeogpoint 'Point(0 0)@2001-01-01')::tgeompoint);
      -- {POINT(0 0)@2001-01-01}

A common way to store temporal points in PostGIS is to represent them as geometries of type `LINESTRING M` and use the M dimension to encode timestamps as seconds since 1970-01-01 00:00:00. These time-enhanced geometries, called trajectories, can be validated with the function `ST_IsValidTrajectory` to verify that the M value is growing from each vertex to the next. Trajectories can be manipulated with the functions `ST_ClosestPointOfApproach`, `ST_DistanceCPA`, and `ST_CPAWithin`. Temporal point values can be converted to/from PostGIS trajectories.

- Convert between a temporal point and a PostGIS trajectory

  `tpoint::geo`

  `geo::tpoint`

      SELECT ST_AsText((tgeompoint 'Point(0 0)@2001-01-01')::geometry);
      -- POINT M (0 0 978307200)
      SELECT ST_AsText((tgeompoint '{Point(0 0)@2001-01-01, Point(1 1)@2001-01-02,
        Point(1 1)@2001-01-03}')::geometry);
      -- MULTIPOINT M (0 0 978307200,1 1 978393600,1 1 978480000)"
      SELECT ST_AsText((tgeompoint '[Point(0 0)@2001-01-01, Point(1 1)@2001-01-02)')::geometry);
      -- LINESTRING M (0 0 978307200,1 1 978393600)
      SELECT ST_AsText((tgeompoint '{[Point(0 0)@2001-01-01, Point(1 1)@2001-01-02),
        [Point(1 1)@2001-01-03, Point(1 1)@2001-01-04),
        [Point(1 1)@2001-01-05, Point(0 0)@2001-01-06)}')::geometry);
      /* MULTILINESTRING M ((0 0 978307200,1 1 978393600),(1 1 978480000,1 1 978566400),
         (1 1 978652800,0 0 978739200)) */
      SELECT ST_AsText((tgeompoint '{[Point(0 0)@2001-01-01, Point(1 1)@2001-01-02),
        [Point(1 1)@2001-01-03],
        [Point(1 1)@2001-01-05, Point(0 0)@2001-01-06)}')::geometry);
      /* GEOMETRYCOLLECTION M (LINESTRING M (0 0 978307200,1 1 978393600),
         POINT M (1 1 978480000),LINESTRING M (1 1 978652800,0 0 978739200)) */

      SELECT asText(geometry 'LINESTRING M (0 0 978307200,0 1 978393600,
        1 1 978480000)'::tgeompoint);
      -- [POINT(0 0)@2001-01-01, POINT(0 1)@2001-01-02, POINT(1 1)@2001-01-03];
      SELECT asText(geometry 'GEOMETRYCOLLECTION M (LINESTRING M (0 0 978307200,1 1 978393600),
        POINT M (1 1 978480000),LINESTRING M (1 1 978652800,0 0 978739200))'::tgeompoint);
      /* {[POINT(0 0)@2001-01-01, POINT(1 1)@2001-01-02], [POINT(1 1)@2001-01-03],
         [POINT(1 1)@2001-01-05, POINT(0 0)@2001-01-06]} */

## Accessors

- Return the memory size in bytes

  `memSize(ttype) → integer`

      SELECT memSize(tint '{1@2001-01-01, 2@2001-01-02, 3@2001-01-03}');
      -- 176

- Return the temporal type

  `tempSubtype(ttype) → {'Instant','Sequence','SequenceSet'}`

      SELECT tempSubtype(tint '[1@2001-01-01, 2@2001-01-02, 3@2001-01-03]');
      -- Sequence

- Return the interpolation

  `interp(ttype) → {'None', 'Discrete','Step','Linear'}`

      SELECT interp(tbool 'true@2001-01-01');
      -- None
      SELECT interp(tfloat '{1@2001-01-01, 2@2001-01-02, 3@2001-01-03}');
      -- Discrete
      SELECT interp(tint '[1@2001-01-01, 2@2001-01-02, 3@2001-01-03]');
      -- Step
      SELECT interp(tfloat '[1@2001-01-01, 2@2001-01-02, 3@2001-01-03]');
      -- Linear
      SELECT interp(tfloat 'Interp=Step;[1@2001-01-01, 2@2001-01-02, 3@2001-01-03]');
      -- Step
      SELECT interp(tgeompoint 'Interp=Step;[Point(1 1)@2001-01-01,
        Point(2 2)@2001-01-02, Point(3 3)@2001-01-03]');
      -- Step

- Return the value or the timestamp of an instant

  `getValue(ttypeInst) → base`

  `getTimestamp(ttypeInst) → timestamptz`

      SELECT getValue(tint '1@2001-01-01');
      -- 1
      SELECT getTimestamp(tfloat '1@2001-01-01');
      -- 2001-01-01

- Return the values or the time on which a temporal value is defined

  `getValues(talpha) → {bool[],spanset,textset}`

  `getTime(ttype) → tstzspanset`

      SELECT getValues(tbool '[false@2001-01-01, true@2001-01-02, false@2001-01-03]');
      -- {f,t}
      SELECT getValues(tint '[1@2001-01-01, 3@2001-01-02, 1@2001-01-03]');
      -- {[1, 2), [3, 4)}
      SELECT getValues(tint '{[1@2001-01-01, 2@2001-01-02, 1@2001-01-03],
        [4@2001-01-04, 4@2001-01-05]}');
      -- {[1, 3), [4, 5)}
      SELECT getValues(tfloat '{1@2001-01-01, 2@2001-01-02, 1@2001-01-03}');
      -- {[1, 1], [2, 2]}
      SELECT getValues(tfloat 'Interp=Step;{[1@2001-01-01, 2@2001-01-02, 1@2001-01-03],
        [3@2001-01-04, 3@2001-01-05]}');
      -- {[1, 1], [2, 2], [3, 3]}
      SELECT getValues(tfloat '[1@2001-01-01, 2@2001-01-02, 1@2001-01-03]');
      -- {[1, 2]}
      SELECT getValues(tfloat '{[1@2001-01-01, 2@2001-01-02, 1@2001-01-03],
        [3@2001-01-04, 3@2001-01-05]}');
      -- {[1, 2], [3, 3]}

      SELECT getTime(ttext 'walking@2001-01-01');
      -- {[2001-01-01, 2001-01-01]}
      SELECT getTime(tfloat '{1@2001-01-01, 2@2001-01-02, 1@2001-01-03}');
      -- {[2001-01-01, 2001-01-01], [2001-01-02, 2001-01-02], [2001-01-03, 2001-01-03]}
      SELECT getTime(tint '[1@2001-01-01, 1@2001-01-15)');
      -- {[2001-01-01, 2001-01-15)}
      SELECT getTime(tfloat '{[1@2001-01-01, 1@2001-01-10), [12@2001-01-12, 12@2001-01-15]}');
      -- {[2001-01-01, 2001-01-10), [2001-01-12, 2001-01-15]}

- Return the value span and the time span ignoring the potential gaps

  `valueSpan(tnumber) → numspan`

  `timeSpan(ttype) → tstzspan`

      SELECT valueSpan(tint '{[1@2001-01-01, 1@2001-01-03), [4@2001-01-03, 6@2001-01-05]}');
      -- [1,7)
      SELECT valueSpan(tfloat '{1@2001-01-01, 2@2001-01-03, 3@2001-01-05}');
      -- [1,3])

      SELECT timeSpan(tint '{1@2001-01-01, 2@2001-01-03, 3@2001-01-05}');
      -- [2001-01-01, 2001-01-05]
      SELECT timeSpan(tfloat '{[1@2001-01-01, 1@2001-01-02), [2@2001-01-03, 3@2001-01-04)}');
      -- [2001-01-01, 2001-01-04)

- Return the values of the temporal number or point as a set

  `valueSet(tnumber, tpoint) → {numset,geoset}`

      SELECT valueSet(tint '[1@2001-01-01, 2@2001-01-03]');
      -- {1, 2}
      SELECT valueSet(tfloat '{[1@2001-01-01, 2@2001-01-03), [3@2001-01-03, 4@2001-01-05)}');
      -- {1, 2, 3, 4}
      SELECT asText(valueSet(tgeompoint '{[Point(0 0)@2001-01-01, Point(0 1)@2001-01-02),
        [Point(0 1)@2001-01-03, Point(1 1)@2001-01-04)}'));
      -- {"POINT(0 0)", "POINT(1 1)", "POINT(0 1)"}

- Return the start, end, or n-th value

  `startValue(ttype) → base`

  `endValue(ttype) → base`

  `valueN(ttype,int) → base`

  The functions do not take into account whether the bounds are inclusive or not.

      SELECT startValue(tfloat '(1@2001-01-01, 2@2001-01-03)');
      -- 1
      SELECT endValue(tfloat '{[1@2001-01-01, 2@2001-01-03), [3@2001-01-03, 5@2001-01-05)}');
      -- 5
      SELECT valueN(tfloat '{[1@2001-01-01, 2@2001-01-03), [3@2001-01-03, 5@2001-01-05)}', 3);
      -- 3

- Return the minimum or maximum value

  `minValue(torder) → base`

  `maxValue(torder) → base`

  The functions do not take into account whether the bounds are inclusive or not.

      SELECT minValue(tfloat '{1@2001-01-01, 2@2001-01-03, 3@2001-01-05}');
      -- 1
      SELECT maxValue(tfloat '{[1@2001-01-01, 2@2001-01-03), [3@2001-01-03, 5@2001-01-05)}');
      -- 5

- Return the instant with the minimum or maximum value

  `minInstant(torder) → base`

  `maxInstant(torder) → base`

  The function does not take into account whether the bounds are inclusive or not. If several instants have the minimum value, the first one is returned.

      SELECT minInstant(tfloat '{1@2001-01-01, 2@2001-01-03, 3@2001-01-05}');
      -- 1@2001-01-01
      SELECT maxInstant(tfloat '{[1@2001-01-01, 2@2001-01-03), [3@2001-01-03, 5@2001-01-05)}');
      -- 5@2001-01-05

- Return the value at a timestamp

  `valueAtTimestamp(ttype,timestamptz) → base`

      SELECT valueAtTimestamp(tfloat '[1@2001-01-01, 4@2001-01-04)', '2001-01-02');
      -- 2

- Return the time interval

  `duration(ttype,boundspan=false) → interval`

  An additional parameter can be set to true to compute the duration of the bounding time span, thus ignoring the potential time gaps

      SELECT duration(tfloat '{1@2001-01-01, 2@2001-01-03, 2@2001-01-05}');
      -- 00:00:00
      SELECT duration(tfloat '{1@2001-01-01, 2@2001-01-03, 2@2001-01-05}', true);
      -- 4 days
      SELECT duration(tfloat '[1@2001-01-01, 2@2001-01-03, 2@2001-01-05)');
      -- 4 days
      SELECT duration(tfloat '{[1@2001-01-01, 2@2001-01-03), [2@2001-01-04, 2@2001-01-05)}');
      -- 3 days
      SELECT duration(tfloat '{[1@2001-01-01, 2@2001-01-03), [2@2001-01-04, 2@2001-01-05)}',
        true);
      -- 4 days

- Is the start/end instant inclusive?

  `lowerInc(ttype) → bool`

  `upperInc(ttype) → bool`

      SELECT lowerInc(tint '[1@2001-01-01, 2@2001-01-02)');
      -- true
      SELECT upperInc(tfloat '{[1@2001-01-01, 2@2001-01-02), (2@2001-01-02, 3@2001-01-03)}');
      -- false

- Return the number of different instants

  `numInstants(ttype) → integer`

      SELECT numInstants(tfloat '{[1@2001-01-01, 2@2001-01-02), (2@2001-01-02, 3@2001-01-03)}');
      -- 3

- Return the start, end, or n-th instant

  `startInstant(ttype) → ttypeInst`

  `endInstant(ttype) → ttypeInst`

  `instantN(ttype,integer) → ttypeInst`

  The functions do not take into account whether the bounds are inclusive or not.

      SELECT startInstant(tfloat '{[1@2001-01-01, 2@2001-01-02),
        (2@2001-01-02, 3@2001-01-03)}');
      -- 1@2001-01-01
      SELECT endInstant(tfloat '{[1@2001-01-01, 2@2001-01-02), (2@2001-01-02, 3@2001-01-03)}');
      -- 3@2001-01-03
      SELECT instantN(tfloat '{[1@2001-01-01, 2@2001-01-02), (2@2001-01-02, 3@2001-01-03)}', 3);
      -- 3@2001-01-03

- Return the different instants

  `instants(ttype) → ttypeInst[]`

      SELECT instants(tfloat '{[1@2001-01-01, 2@2001-01-02), (2@2001-01-02, 3@2001-01-03)}');
      -- {"1@2001-01-01","2@2001-01-02","3@2001-01-03"}

- Return the number of different timestamps

  `numTimestamps(ttype) → integer`

      SELECT numTimestamps(tfloat '{[1@2001-01-01, 2@2001-01-03),
        [3@2001-01-03, 5@2001-01-05)}');
      -- 3

- Return the start, end, or n-th timestamp

  `startTimestamp(ttype) → timestamptz`

  `endTimestamp(ttype) → timestamptz`

  `timestampN(ttype,integer) → timestamptz`

  The functions do not take into account whether the bounds are inclusive or not.

      SELECT startTimestamp(tfloat '[1@2001-01-01, 2@2001-01-03)');
      -- 2001-01-01
      SELECT endTimestamp(tfloat '{[1@2001-01-01, 2@2001-01-03),
        [3@2001-01-03, 5@2001-01-05)}');
      -- 2001-01-05
      SELECT timestampN(tfloat '{[1@2001-01-01, 2@2001-01-03),
        [3@2001-01-03, 5@2001-01-05)}', 3);
      -- 2001-01-05

- Return the different timestamps

  `timestamps(ttype) → timestamptz[]`

      SELECT timestamps(tfloat '{[1@2001-01-01, 2@2001-01-03), [3@2001-01-03, 5@2001-01-05)}');
      -- {"2001-01-01", "2001-01-03", "2001-01-05"}

- Return the number of sequences

  `numSequences({ttypeContSeq,ttypeSeqSet}) → integer`

      SELECT numSequences(tfloat '{[1@2001-01-01, 2@2001-01-03),
        [3@2001-01-03, 5@2001-01-05)}');
      -- 2

- Return the start, end, or n-th sequence

  `startSequence({ttypeContSeq,ttypeSeqSet}) → ttypeContSeq`

  `endSequence({ttypeContSeq,ttypeSeqSet}) → ttypeContSeq`

  `sequenceN({ttypeContSeq,ttypeSeqSet},integer) → ttypeContSeq`

      SELECT startSequence(tfloat '{[1@2001-01-01, 2@2001-01-03),
        [3@2001-01-03, 5@2001-01-05)}');
      -- [1@2001-01-01, 2@2001-01-03)
      SELECT endSequence(tfloat '{[1@2001-01-01, 2@2001-01-03), [3@2001-01-03, 5@2001-01-05)}');
      -- [3@2001-01-03, 5@2001-01-05)
      SELECT sequenceN(tfloat '{[1@2001-01-01, 2@2001-01-03),
        [3@2001-01-03, 5@2001-01-05)}', 2);
      -- [3@2001-01-03, 5@2001-01-05)

- Return the sequences

  `sequences({ttypeContSeq,ttypeSeqSet}) → ttypeContSeq[]`

      SELECT sequences(tfloat '{[1@2001-01-01, 2@2001-01-03), [3@2001-01-03, 5@2001-01-05)}');
      -- {"[1@2001-01-01, 2@2001-01-03)", "[3@2001-01-03, 5@2001-01-05)"}

- Return the segments

  `segments({ttypeContSeq,ttypeSeqSet}) → ttypeContSeq[]`

      SELECT segments(tint '{[1@2001-01-01, 3@2001-01-02, 2@2001-01-03],
        (3@2001-01-03, 5@2001-01-05]}');
      /* {"[1@2001-01-01, 1@2001-01-02)","[3@2001-01-02, 3@2001-01-03)","[2@2001-01-03]",
         "(3@2001-01-03, 3@2001-01-05)","[5@2001-01-05]"} */
      SELECT segments(tfloat '{[1@2001-01-01, 3@2001-01-02, 2@2001-01-03],
        (3@2001-01-03, 5@2001-01-05]}');
      /* {"[1@2001-01-01, 3@2001-01-02)","[3@2001-01-02, 2@2001-01-03]",
         "(3@2001-01-03, 5@2001-01-05]"} */

- Return the area under the curve

  `integral(tnumber) → float`

      SELECT  integral(tint '[1@2001-01-01,2@2001-01-02]') / (24 * 3600 * 1e6);
      -- 1
      SELECT integral(tfloat '[1@2001-01-01,2@2001-01-02]') / (24 * 3600 * 1e6);
      -- 1.5

- Return the time-weighted average

  `twAvg(tnumber) → float`

      SELECT twAvg(tfloat '{[1@2001-01-01, 2@2001-01-03), [2@2001-01-04, 2@2001-01-06)}');
      -- 1.75

## Transformations

A temporal value can be transformed to another subtype. An error is raised if the subtypes are incompatible.

- Transform a temporal value to another subtype

  `ttypeInst(ttype) → ttypeInst`

  `ttypeSeq(ttype) → ttypeSeq`

  `ttypeSeqSet(ttype) → ttypeSeqSet`

      SELECT tboolInst(tbool '{[true@2001-01-01]}');
      -- t@2001-01-01
      SELECT tboolInst(tbool '{[true@2001-01-01, true@2001-01-02]}');
      -- ERROR: Cannot transform input value to a temporal instant
      SELECT tintSeq(tint '1@2001-01-01');
      -- [1@2001-01-01]
      SELECT tfloatSeqSet(tfloat '2.5@2001-01-01');
      -- {[2.5@2001-01-01]}
      SELECT tfloatSeqSet(tfloat '{2.5@2001-01-01, 1.5@2001-01-02, 3.5@2001-01-03}');
      -- {[2.5@2001-01-01],[1.5@2001-01-02],[3.5@2001-01-03]}

- Transform a temporal value to another interpolation

  `setInterp(ttype, interp) → ttype`

      SELECT setInterp(tbool 'true@2001-01-01','discrete');
      -- {t@2001-01-01}
      SELECT setInterp(tfloat '{[1@2001-01-01], [2@2001-01-02], [1@2001-01-03]}', 'discrete');
      -- {1@2001-01-01, 2@2001-01-02, 1@2001-01-03}
      SELECT setInterp(tfloat 'Interp=Step;[1@2001-01-01, 2@2001-01-02,
        1@2001-01-03, 2@2001-01-04]', 'linear');
      /* {[1@2001-01-01, 1@2001-01-02), [2@2001-01-02, 2@2001-01-03),
         [1@2001-01-03, 1@2001-01-04), [2@2001-01-04]} */
      SELECT asText(setInterp(tgeompoint 'Interp=Step;{[Point(1 1)@2001-01-01,
        Point(2 2)@2001-01-02], [Point(3 3)@2001-01-05, Point(4 4)@2001-01-06]}', 'linear'));
      /* {[POINT(1 1)@2001-01-01, POINT(1 1)@2001-01-02), [POINT(2 2)@2001-01-02],
         [POINT(3 3)@2001-01-05, POINT(3 3)@2001-01-06), [POINT(4 4)@2001-01-06]} */

- Shift the value or time span of a temporal value by a value or interval

  `shiftValue(tnumber,base) → tnumber`

  `shiftTime(ttype,interval) → ttype`

      SELECT shiftValue(tint '{1@2001-01-01, 2@2001-01-03, 1@2001-01-05}', 1);
      -- {2@2001-01-02, 3@2001-01-04, 2@2001-01-06}
      SELECT shiftValue(tfloat '{[1@2001-01-01,2@2001-01-02],[3@2001-01-03,4@2001-01-04]}', -1);
      --  {[0@2001-01-01, 1@2001-01-02], [2@2001-01-03, 3@2001-01-04]}

      SELECT shiftTime(tint '{1@2001-01-01, 2@2001-01-03, 1@2001-01-05}', '1 day');
      -- {1@2001-01-02, 2@2001-01-04, 1@2001-01-06}
      SELECT shiftTime(tfloat '[1@2001-01-01, 2@2001-01-03]', '1 day');
      -- [1@2001-01-02, 2@2001-01-04]
      SELECT asText(shiftTime(tgeompoint '{[Point(1 1)@2001-01-01, Point(2 2)@2001-01-03],
        [Point(2 2)@2001-01-04, Point(1 1)@2001-01-05]}', '1 day'));
      /* {[POINT(1 1)@2001-01-02, POINT(2 2)@2001-01-04],
         [POINT(2 2)@2001-01-05, POINT(1 1)@2001-01-06]} */

- Scale the value or time span of a temporal value to a value or interval

  `scaleValue(tnumber,width) → tnumber`

  `scaleTime(ttype,interval) → ttype`

  If the value or time span of the temporal value is zero (for example, for a temporal instant), the result is the temporal value. The given width or interval must be strictly greater than zero.

      SELECT scaleValue(tint '1@2001-01-01', 1);
      -- 1@2001-01-01
      SELECT scaleValue(tfloat '{[1@2001-01-01,2@2001-01-02], [3@2001-01-03,4@2001-01-04]}', 6);
      -- {[1@2001-01-01, 3@2001-01-03], [5@2001-01-05, 7@2001-01-07]}
      SELECT scaleValue(tint '1@2001-01-01', -1);
      -- ERROR:   The value must be strictly positive: -1

      SELECT scaleTime(tint '1@2001-01-01', '1 day');
      -- 1@2001-01-01
      SELECT scaleTime(tint '{1@2001-01-01, 2@2001-01-03, 1@2001-01-05}', '1 day');
      -- {1@2001-01-01 00:00:00+01, 2@2001-01-01 12:00:00+01, 1@2001-01-02 00:00:00+01}
      SELECT scaleTime(tfloat '[1@2001-01-01, 2@2001-01-03]', '1 day');
      -- [1@2001-01-01, 2@2001-01-02]
      SELECT asText(scaleTime(tgeompoint '{[Point(1 1)@2001-01-01, Point(2 2)@2001-01-02,
        Point(1 1)@2001-01-03], [Point(2 2)@2001-01-04, Point(1 1)@2001-01-05]}', '1 day'));
      /* {[POINT(1 1)@2001-01-01 00:00:00+01, POINT(2 2)@2001-01-01 06:00:00+01,
         POINT(1 1)@2001-01-01 12:00:00+01], [POINT(2 2) @2001-01-01 18:00:00+01,
         POINT(1 1)@2001-01-02 00:00:00+01]} */
      SELECT scaleTime(tint '1@2001-01-01', '-1 day');
      -- ERROR:  The interval must be positive: -1 days

- Shift and scale the value or time span of a temporal value to the two values or intervals

  `shiftScaleValue(tnumber,base,base) → tnumber`

  `shiftScaleTime(ttype,interval,interval) → ttype`

  These functions combine the functions `shiftValue` and `scaleValue` or `shiftTime` and `scaleTime`.

      SELECT shiftScaleValue(tint '1@2001-01-01', 1, 1);
      -- 2@2001-01-01
      SELECT shiftScaleValue(tfloat '{[1@2001-01-01,2@2001-01-02],[3@2001-01-03,4@2001-01-04]}',
        -1, 6);
      --  {[0@2001-01-01, 2@2001-01-02], [4@2001-01-03, 6@2001-01-04]}

      SELECT shiftScaleTime(tint '1@2001-01-01', '1 day', '1 day');
      -- 1@2001-01-02
      SELECT shiftScaleTime(tint '{1@2001-01-01, 2@2001-01-03, 1@2001-01-05}', '1 day','1 day');
      -- {1@2001-01-02 00:00:00+01, 2@2001-01-02 12:00:00+01, 1@2001-01-03 00:00:00+01}
      SELECT shiftScaleTime(tfloat '[1@2001-01-01, 2@2001-01-03]', '1 day', '1 day');
      -- [1@2001-01-02, 2@2001-01-03]
      SELECT asText(shiftScaleTime(tgeompoint '{[Point(1 1)@2001-01-01, Point(2 2)@2001-01-02,
        Point(1 1)@2001-01-03], [Point(2 2)@2001-01-04, Point(1 1)@2001-01-05]}',
        '1 day', '1 day'));
      /* {[POINT(1 1)@2001-01-02 00:00:00+01, POINT(2 2)@2001-01-02 06:00:00+01,
         POINT(1 1)@2001-01-02 12:00:00+01], [POINT(2 2) @2001-01-02 18:00:00+01,
         POINT(1 1)@2001-01-03 00:00:00+01]} */

- Extract from a temporal sequence (set) with linear interpolation the subsequences where the objects stays within an area with a specified maximum size (`maxDist`) for at least the given duration (`minDuration`) &Z_support; &geography_support;

  `stops({tcontSeq,ttypeSeqSet},maxDist=0.0,minDuration='0 minutes') → ttypeSeqSet`

  For spatial types, the size of the area is computed as the diagonal of the minimum rotated rectangle of the points in the subsequence. For scalar types, the size is computed as the width of the enclosing interval. If `maxDist` is not given it is assumed 0.0 and thus, the function extracts the constant segments of the given temporal value. For temporal points, the distance is computed in the units of the coordinate system. Note that even though the function accepts 3D geometries, the computation is always performed in 2D.

      SELECT stops(tfloat '[1@2001-01-01, 1@2001-01-02, 2@2001-01-03]');
      -- {[1@2001-01-01, 1@2001-01-02)}
      SELECT stops(tfloat '[1@2001-01-01, 1@2001-01-02, 2@2001-01-03]', 0.0, '2 days');
      -- NULL
      SELECT asText(stops(tgeompoint '[Point(1 1)@2001-01-01, Point(1 1)@2001-01-02,
        Point(2 2)@2001-01-03, Point(2 2)@2001-01-04]'));
      /* {[POINT(1 1)@2001-01-01, POINT(1 1)@2001-01-02), [POINT(2 2)@2001-01-03,
         POINT(2 2)@2001-01-04]} */
      SELECT asText(stops(tgeompoint '[Point(1 1 1)@2001-01-01, Point(1 1 1)@2001-01-02,
        Point(2 2 2)@2001-01-03, Point(2 2 2)@2001-01-04]', 1.75));
      /* {[POINT Z (1 1 1)@2001-01-01, POINT Z (1 1 1)@2001-01-02, POINT Z (2 2 2)@2001-01-03,
         POINT Z (2 2 2)@2001-01-04]} */

- Transform a nonlinear temporal value into a set of rows, each one is a pair composed of a base value and a period set during which the temporal value has the base value &SRF;

  `unnest(ttype) → {(value,time)}`

      SELECT (un).value, (un).time
      FROM (SELECT unnest(tfloat '{1@2001-01-01, 2@2001-01-02, 1@2001-01-03}') AS un) t;
      -- 1 | {[2001-01-01, 2001-01-01], [2001-01-03, 2001-01-03]}
      -- 2 | {[2001-01-02, 2001-01-02]}
      SELECT (un).value, (un).time
      FROM (SELECT unnest(tint '[1@2001-01-01, 2@2001-01-02, 1@2001-01-03]') AS un) t;
      -- 1 | {[2001-01-01, 2001-01-02), [2001-01-03, 2001-01-03]}
      -- 2 | {[2001-01-02, 2001-01-03)}
      SELECT (un).value, (un).time
      FROM (SELECT unnest(tfloat '[1@2001-01-01, 2@2001-01-02, 1@2001-01-03]') AS un) t;
      -- ERROR:  The temporal value cannot have linear interpolation
      SELECT ST_AsText((un).value), (un).time
      FROM (SELECT unnest(tgeompoint 'Interp=Step;[Point(1 1)@2001-01-01,
        Point(2 2)@2001-01-02, Point(1 1)@2001-01-03]') AS un) t;
      --  POINT(1 1) | {[2001-01-01, 2001-01-02), [2001-01-03, 2001-01-03]}
      --  POINT(2 2) | {[2001-01-02, 2001-01-03)}