# Temporal Types (Part 1)

## Introduction

MobilityDB provides several temporal types based on PostgreSQL or PostGIS types, namely, `tbool`, `tint`, `tfloat`, `ttext`, `tgeometry`, `tgeography`, `tgeompoint`, and `tgeogpoint`, which are, respectively, based on the base types `bool`, `integer`, `float`, `text`, `geometry`, and `geography`, where `tgeometry` and `tgeography` accept arbitrary geometries/geographies, while `tgeompoint` and `tgeogpoint` only accept 2D or 3D points with Z dimension. In addition, MobilityDB provides other specific spatial types, namely, `cbuffer` (circular buffer), `npoint` (network point), and `pose`, and its corresponding spatiotemporal types, namely, `tcbuffer`, `tnpoint`, `tpose` and `trgeometry` (temporal rigid geometry). In this chapter and the next one we present the functions and operators available for all temporal types, while the specific functions for the spatiotemporal types will be given in subsequenct chapters.

The interpolation of a temporal value states how the value evolves between successive instants. The interpolation is discrete when the value is unknown between two successive instants. They can represent, for example, checkins/checkouts when using an RFID card reader to enter or exit a building. The interpolation is step when the value remains constant between two successive instants. For example, the gear used by a moving car may be represented with a temporal integer, which indicates that its value is constant between two time instants. On the other hand, the interpolation is linear when the value evolves linearly between two successive instants. For example, the speed of a car may be represented with a temporal float, which indicates that the values are known at the time instants but continuously evolve between them. Similarly, the location of a vehicule may be represented by a temporal point where the location between two consecutive GPS readings is obtained by linear interpolation. Temporal types based on discrete base types, that is the `tbool`, `tint`, or `ttext` evolve necesssarily in a step manner. On the other hand, temporal types based on continuous base types, that is `tfloat`, `tgeompoint`, or `tgeogpoint` may evolve in a step or linear manner. Note that the types `tgeometry` and `tgeography` only support discrete or step interpolation, since it is not possible to linearly interpolate two arbitrary geometries/geographies.

The subtype of a temporal value states the temporal extent at which the evolution of values is recorded. Temporal values come in three subtypes, explained next.

A temporal value of instant subtype (briefly, an instant value) represents the value at a time instant, for example

    SELECT tfloat '17@2018-01-01 08:00:00';

A temporal value of sequence subtype (briefly, a sequence value) represents the evolution of the value during a sequence of time instants, where the values between these instants are interpolated using a discrete, step, or a linear function (see above). An example is as follows:

    -- Discrete interpolation
    SELECT tfloat '{17@2018-01-01 08:00:00, 17.5@2018-01-01 08:05:00, 18@2018-01-01 08:10:00}';
    -- Step interpolation
    SELECT tfloat 'Interp=Step;(10@2018-01-01 08:00:00, 20@2018-01-01 08:05:00,
      15@2018-01-01 08:10:00]';
    -- Linear interpolation
    SELECT tfloat '(10@2018-01-01 08:00:00, 20@2018-01-01 08:05:00, 15@2018-01-01 08:10:00]';

As can be seen, a sequence value has a lower and an upper bound that can be inclusive (represented by ‘`[`’ and ‘`]`’) or exclusive (represented by ‘`(`' and ‘`)`'). By definition, both bounds must be inclusive when the interpolation is discrete or when the sequence has a single instant (called an instantaneous sequence), as the next example

    SELECT tint '[10@2018-01-01 08:00:00]';

Sequence values must be uniform, that is, they must be composed of instant values of the same base type. Sequence values with step or linear interpolation are referred to as continuous sequences.

The value of a temporal sequence is interpreted by assuming that the period of time defined by every pair of consecutive values `v1@t1` and `v2@t2` is lower inclusive and upper exclusive, unless they are the first or the last instants of the sequence and in that case the bounds of the whole sequence apply. Furthermore, the value taken by the temporal sequence between two consecutive instants depends on whether the interpolation is step or linear. For example, the temporal sequence above represents that the value is `10` during `(2018-01-01 08:00:00, 2018-01-01 08:05:00)`, `20` during `[2018-01-01 08:05:00, 2018-01-01 08:10:00)`, and `15` at the end instant `2018-01-01 08:10:00`. On the other hand, the following temporal sequence

    SELECT tfloat '(10@2018-01-01 08:00:00, 20@2018-01-01 08:05:00, 15@2018-01-01 08:10:00]';

represents that the value evolves linearly from `10` to `20` during `(2018-01-01 08:00:00, 2018-01-01 08:05:00)` and evolves from `20` to `15` during `[2018-01-01 08:05:00, 2018-01-01 08:10:00]`.

Finally, a temporal value of sequence set subtype (briefly, a sequence set value) represents the evolution of the value at a set of sequences, where the values between these sequences are unknown. An example is as follows:

    SELECT tfloat '{[17@2018-01-01 08:00:00, 17.5@2018-01-01 08:05:00],
      [18@2018-01-01 08:10:00, 18@2018-01-01 08:15:00]}';

As shown in the above examples, sequence set values can only be of step or linear interpolation. Furtheremore, all composing sequences of a sequence set value must be of the same base type and the same interpolation.

Continuous sequence values are converted into normal form so that equivalent values have identical representations. For this, consecutive instant values are merged when possible. For step interpolation, three consecutive instant values can be merged into two if they have the same value. For linear interpolation, three consecutive instant values can be merged into two if the linear functions defining the evolution of values are the same. Examples of transformation into normal form are as follows.

    SELECT tint '[1@2001-01-01, 2@2001-01-03, 2@2001-01-04, 2@2001-01-05)';
    -- [1@2001-01-01 00:00:00+00, 2@2001-01-03 00:00:00+00, 2@2001-01-05 00:00:00+00)
    SELECT asText(tgeompoint '[Point(1 1)@2001-01-01 08:00:00, Point(1 1)@2001-01-01 08:05:00,
      Point(1 1)@2001-01-01 08:10:00)');
    -- [Point(1 1)@2001-01-01 08:00:00, Point(1 1)@2001-01-01 08:10:00)
    SELECT tfloat '[1@2001-01-01, 2@2001-01-03, 3@2001-01-05]';
    -- [1@2001-01-01 00:00:00+00, 3@2001-01-05 00:00:00+00]
    SELECT asText(tgeompoint '[Point(1 1)@2001-01-01 08:00:00, Point(2 2)@2001-01-01 08:05:00,
      Point(3 3)@2001-01-01 08:10:00]');
    -- [Point(1 1)@2001-01-01 08:00:00, Point(3 3)@2001-01-01 08:10:00]

Similary, temporal sequence set values are converted into normal form. For this, consecutive sequence values are merged when possible. Examples of transformation into a normal form are as follows.

    SELECT tint '{[1@2001-01-01, 1@2001-01-03), [2@2001-01-03, 2@2001-01-05)}';
    -- '{[1@2001-01-01, 2@2001-01-03, 2@2001-01-05)}'
    SELECT tfloat '{[1@2001-01-01, 2@2001-01-03), [2@2001-01-03, 3@2001-01-05]}';
    -- '{[1@2001-01-01, 3@2001-01-05]}'
    SELECT tfloat '{[1@2001-01-01, 3@2001-01-05), [3@2001-01-05]}';
    -- '{[1@2001-01-01, 3@2001-01-05]}'
    SELECT asText(tgeompoint '{[Point(0 0)@2001-01-01 08:00:00,
      Point(1 1)@2001-01-01 08:05:00, Point(1 1)@2001-01-01 08:10:00),
      [Point(1 1)@2001-01-01 08:10:00, Point(1 1)@2001-01-01 08:15:00)}');
    /* {[[Point(0 0)@2001-01-01 08:00:00, Point(1 1)@2001-01-01 08:05:00,
       Point(1 1)@2001-01-01 08:15:00)} */
    SELECT asText(tgeompoint '{[Point(1 1)@2001-01-01 08:00:00,Point(2 2)@2001-01-01 08:05:00),
      [Point(2 2)@2001-01-01 08:05:00, Point(3 3)@2001-01-01 08:10:00]}');
    -- {[Point(1 1)@2001-01-01 08:00:00, Point(3 3)@2001-01-01 08:10:00]}
    SELECT asText(tgeompoint '{[Point(1 1)@2001-01-01 08:00:00,Point(3 3)@2001-01-01 08:10:00),
      [Point(3 3)@2001-01-01 08:10:00]}');
    -- {[Point(1 1)@2001-01-01 08:00:00, Point(3 3)@2001-01-01 08:10:00]}

Temporal types support type modifiers (or `typmod` in PostgreSQL terminology), which specify additional information for a column definition. For example, in the following table definition:

    CREATE TABLE Department(DeptNo integer, DeptName varchar(25), NoEmps tint(Sequence));

the type modifier for the type `varchar` is the value 25, which indicates the maximum length of the values of the column, while the type modifier for the type `tint` is the string `Sequence`, which restricts the subtype of the values of the column to be sequences. In the case of temporal alphanumeric types (that is, `tbool`, `tint`, `tfloat`, and `ttext`), the possible values for the type modifier are `Instant`, `Sequence`, and `SequenceSet`. If no type modifier is specified for a column, values of any subtype are allowed.

On the other hand, in the case of temporal geometry types (that is, `tgeompoint` `tgeogpoint`, `tgeometry`, or `tgeography`) the type modifier may be used to specify the subtype, the geometry type, and/or the spatial reference identifier (SRID). For example, in the following table definition:

    CREATE TABLE Flight(FlightNo integer, Route tgeogpoint(Sequence, PointZ, 4326));
    CREATE TABLE Storm(StormId integer, Route tgeography(Sequence, Linestring, 4326));

the type modifiers for the `tgeogpoint` and `tgeography` types are composed of three values, the first one indicating the subtype as above, the second one the spatial type of the geographies composing the temporal point and geographies, and the last one the SRID of the composing geographies. For temporal points, the possible values for the first argument of the type modifier are as above, those for the second argument are either `Point` or `PointZ`, and those for the third argument are valid SRIDs. All the three arguments are optional and if any of them is not specified for a column, values of any subtype, dimensionality, and/or SRID are allowed.

Each temporal type is associated to another type, referred to as its bounding box, which represent its extent in the value and/or the time dimension. The bounding box of the various temporal types are as follows:

- The `tstzspan` type for the `tbool` and `ttext` types, where only the temporal extent is considered.

- The `tbox` (temporal box) type for the `tint` and `tfloat` types, where the value and the time extents are defined, respectively, by a number span and a time span.

- The `stbox` (spatiotemporal box) type for the `tgeompoint` and `tgeogpoint` types, where the spatial extent is defined in the X, Y, and Z dimensions, and the time extent by a time span.

A rich set of functions and operators is available to perform various operations on temporal types. They are explained in this chapter and the following ones. Some of these operations, in particular those related to indexes, manipulate bounding boxes for efficiency reasons.

## Examples of Temporal Types

Examples of usage of temporal alphanumeric types are given next.

    CREATE TABLE Department(DeptNo integer, DeptName varchar(25), NoEmps tint);
    INSERT INTO Department VALUES
      (10, 'Research', tint '[10@2001-01-01, 12@2001-04-01, 12@2001-08-01)'),
      (20, 'Human Resources', tint '[4@2001-02-01, 6@2001-06-01, 6@2001-10-01)');
    CREATE TABLE Temperature(RoomNo integer, Temp tfloat);
    INSERT INTO Temperature VALUES
      (1001, tfloat '{18.5@2001-01-01 08:00:00, 20.0@2001-01-01 08:10:00}'),
      (2001, tfloat '{19.0@2001-01-01 08:00:00, 22.5@2001-01-01 08:10:00}');

    -- Value at a timestamp
    SELECT RoomNo, valueAtTimestamp(Temp, '2001-01-01 08:10:00')
    FROM temperature;
    -- 1001 | 20
    -- 2001 | 22.5

    -- Restriction to a value
    SELECT DeptNo, atValues(NoEmps, 10)
    FROM Department;
    -- 10 | [10@2001-01-01, 10@2001-04-01)
    -- 20 |

    -- Restriction to a period
    SELECT DeptNo, atTime(NoEmps, tstzspan '[2001-01-01, 2001-04-01]')
    FROM Department;
    -- 10 | [10@2001-01-01, 12@2001-04-01]
    -- 20 | [4@2001-02-01, 4@2001-04-01]

    -- Temporal comparison
    SELECT DeptNo, NoEmps #<= 10
    FROM Department;
    -- 10 | [t@2001-01-01, f@2001-04-01, f@2001-08-01)
    -- 20 | [t@2001-02-01, t@2001-10-01)

    -- Temporal aggregation
    SELECT tsum(NoEmps)
    FROM Department;
    /* {[10@2001-01-01, 14@2001-02-01, 16@2001-04-01,
       18@2001-06-01, 6@2001-08-01, 6@2001-10-01)} */

Examples of usage of temporal point types are given next.

    CREATE TABLE Trips(CarId integer, TripId integer, Trip tgeompoint);
    INSERT INTO Trips VALUES
      (10, 1, tgeompoint '{[Point(0 0)@2001-01-01 08:00:00, Point(2 0)@2001-01-01 08:10:00,
    Point(2 1)@2001-01-01 08:15:00)}'),
      (20, 1, tgeompoint '{[Point(0 0)@2001-01-01 08:05:00, Point(1 1)@2001-01-01 08:10:00,
      Point(3 3)@2001-01-01 08:20:00)}');

    -- Value at a given timestamp
    SELECT CarId, ST_AsText(valueAtTimestamp(Trip, timestamptz '2001-01-01 08:10:00'))
    FROM Trips;
    -- 10 | POINT(2 0)
    -- 20 | POINT(1 1)

    -- Restriction to a value
    SELECT CarId, asText(atValues(Trip, geometry 'Point(2 0)'))
    FROM Trips;
    -- 10 | {"[POINT(2 0)@2001-01-01 08:10:00+00]"}
    -- 20 |

    -- Restriction to a period
    SELECT CarId, asText(atTime(Trip, tstzspan '[2001-01-01 08:05:00,2001-01-01 08:10:00]'))
    FROM Trips;
    -- 10 | {[POINT(1 0)@2001-01-01 08:05:00+00, POINT(2 0)@2001-01-01 08:10:00+00]}
    -- 20 | {[POINT(0 0)@2001-01-01 08:05:00+00, POINT(1 1)@2001-01-01 08:10:00+00]}

    -- Temporal distance
    SELECT T1.CarId, T2.CarId, T1.Trip <-> T2.Trip
    FROM Trips T1, Trips T2
    WHERE T1.CarId < T2.CarId;
    /* 10 | 20 | {[1@2001-01-01 08:05:00+00, 1.4142135623731@2001-01-01 08:10:00+00,
       1@2001-01-01 08:15:00+00)} */

## Validity of Temporal Types

Values of temporal types must satisfy several constraints so that they are well defined. These constraints are given next.

- The constraints on the base type and the `timestamptz` type must be satisfied.

- A sequence value must be composed of at least one instant value.

- An instantaneous sequence value or a sequence value with discrete interpolation must have inclusive lower and upper bounds.

- In a sequence value, the timestamps of the composing instants must be different and ordered.

- In a sequence value with step interpolation, the last two values must be equal if upper bound is exclusive.

- A sequence set value must be composed of at least one sequence value.

- In a sequence set value, the composing sequence values must be non overlapping and ordered.

An error is raised whenever one of these constraints are not satisfied. Examples of incorrect temporal values are as follows.

    -- Incorrect value for base type
    SELECT tbool '1.5@2001-01-01 08:00:00';
    -- Base type value is not a point
    SELECT tgeompoint 'Linestring(0 0,1 1)@2001-01-01 08:05:00';
    -- Incorrect timestamp
    SELECT tint '2@2001-02-31 08:00:00';
    -- Empty sequence
    SELECT tint '';
    -- Incorrect bounds for instantaneous sequence
    SELECT tint '[1@2001-01-01 09:00:00)';
    -- Duplicate timestamps
    SELECT tint '[1@2001-01-01 08:00:00, 2@2001-01-01 08:00:00]';
    -- Unordered timestamps
    SELECT tint '[1@2001-01-01 08:10:00, 2@2001-01-01 08:00:00]';
    -- Incorrect end value for step interpolation
    SELECT tint '[1@2001-01-01 08:00:00, 2@2001-01-01 08:10:00)';
    -- Empty sequence set
    SELECT tint '{[]}';
    -- Duplicate timestamps
    SELECT tint '{1@2001-01-01 08:00:00, 2@2001-01-01 08:00:00}';
    -- Overlapping periods
    SELECT tint '{[1@2001-01-01 08:00:00, 1@2001-01-01 10:00:00),
      [2@2001-01-01 09:00:00, 2@2001-01-01 11:00:00)}';

## Temporalizing Operations

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 temporal 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.

## Notation

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,

- `ttypeInst`, `ttypeSeq`, and `ttypeSeqSet` represent any temporal type with, respectively, instant, sequence, and sequence set subtype,

- `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`,

- `ttypeDiscSeq` and `ttypeContSeq` represent any temporal type with sequence subtype and, respectively, discrete and continuous interpolation,

- `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`

- `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, `tintSeq` or `tfloatSeq` are represented by `ttypeSeq`.

## 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';
    SELECT tgeometry 'Linestring(0 0,1 1)@2017-01-01 08:00:05';
    SELECT tgeography 'Polygon((0 0,1 1,2 0,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}';
    SELECT tgeometry '{Point(0 0)@2017-01-01 08:00:00,
      Linestring(0 0,0 1)@2017-01-02 08:05:00}';
    SELECT tgeography '{Point(0 0)@2017-01-01 08:00:00,
      Polygon((0 0,1 1,2 0,0 0))@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)';
    SELECT tgeometry '[Point(0 0)@2017-01-01 08:00:00,
      Linestring(0 0,0 1)@2017-01-02 08:05:00]';
    SELECT tgeography '[Point(0 0)@2017-01-01 08:00:00,
      Polygon((0 0,1 1,2 0,0 0))@2017-01-02 08:05: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)}';
    SELECT tgeometry
      '{[Point(0 0)@2017-01-01 08:00:00, Linestring(0 0,1 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 tgeography
      '{[Point(0 0)@2017-01-01 08:00:00, Polygon((0 0,1 1,2 0,0 0))@2017-01-01 08:05:00),
        [Point(0 1)@2017-01-01 08:10:00, Linestring(0 0,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 geometries, 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]'
    SELECT tgeography 'SRID=7844;[Point(0 0)@2001-01-01,Linestring(1 0,0 1)@2001-01-02]'

All component geometries of a temporal geometry 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 tgeography 'SRID=7844;[SRID=4326;Point(0 0)@2001-01-01,
      SRID=4326;Linestring(1 0,0 1)@2001-01-02]';
    -- ERROR: Geometry SRID (4326) does not match temporal type SRID (7844)

If not specified, the default SRID for temporal geometric points is 0 (unknown) and for temporal geographies is 4326 (WGS 84). Temporal geometries 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 geometries are detailed in tgeo_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(ttype,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]
      SELECT asText(tgeometry
        '[Point(1.55 1.55)@2001-01-01,Linestring(1.55 1.55,3.55 3.55)@2001-01-02]', 0);
      -- [Point(1 1)@2001-01-01, Linestring(1 1,3 3)@2001-01-02]

- 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"} */
      SELECT asMFJSON(tgeometry '{[Point(1 1)@2001-01-01 18:00:00+02,
        Linestring(1 1,2 2)@2001-01-01 18:10:00+02]}');
      /* {"type":"MovingGeometry","sequences":[{"values":[{"type":"Point",
          "coordinates":[1,1]},{"type":"LineString","coordinates":[[1,1],[2,2]]}],
          "datetimes":["2001-01-01T17:00:00+01","2001-01-01T17:10:00+01"],
          "lower_inc":true,"upper_inc":true}],"interpolation":"Step"} */

- Return the Well-Known Binary (WKB) or the Hexadecimal Well-Known Binary (WKB) representation

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

  `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 asBinary(tbool 'true@2001-01-01');
      -- \x011a000101009c57d3c11c0000
      SELECT asBinary(tfloat '1.5@2001-01-01');
      -- \x01210001000000000000f83f009c57d3c11c0000
      SELECT asHexWKB(tint '1@2001-01-01', 'XDR');
      -- 000023010000000100001CC1D3579C00
      SELECT asHexWKB(ttext 'AAA@2001-01-01');
      -- 01290001040000000000000041414100009C57D3C11C0000

- Input from the 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]}');
      SELECT asText(tgeometryFromMFJSON(text
        '{"type":"MovingGeometry","sequences":[{"values":[{"type":"Point",
        "coordinates":[1,1]},{"type":"LineString","coordinates":[[1,1],[2,2]]}],
        "datetimes":["2001-01-01T17:00:00+01","2001-01-01T17:10:00+01"],
        "lower_inc":true,"upper_inc":true}],"interpolation":"Step"}'));
      -- {[POINT(1 1)@2001-01-01 17:00:00, LINESTRING(1 1,2 2)@2001-01-01 17:10:00]}

- Input from the Well-Known Binary (WKB) or from the Hexadecimal Extended Well-Known Binary (HexEWKB) representation

  `ttypeFromBinary(bytea) → ttype`

  `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 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
      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

## 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 tgeography('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 tgeographySeq(ARRAY[tgeography '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 tgeographySeqSet(ARRAY[tgeography
        '[Point(0 0)@2001-01-01 08:00:00, Point(0 0)@2001-01-01 08:05:00)',
        '[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 geometries, 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(tgeometrySeqSetGaps(ARRAY[tgeometry 'Point(1 1)@2001-01-01',
        'Linestring(2 2,3 3)@2001-01-02', 'Point(4 2)@2001-01-03',
        'Polygon((5 0,6 1,7 0,5 0))@2001-01-05'], '1 day', 1));
      /* {[POINT(1 1)@2001-01-01], [LINESTRING(2 2,3 3)@2001-01-02],
         [POINT(4 2)@2001-01-03], [POLYGON((5 0,6 1,7 0,5 0))@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 timestamptz span

  `ttype::tstzspan`

      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]

## 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
      SELECT interp(tgeometry '[Point(1 1)@2001-01-01,
        Linestring(1 1,2 2)@2001-01-02, Polygon((3 3,4 4,5 3,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(ttype) → baseset`

  `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 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 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`

  `instants(ttype) → ttypeInst[]`

      SELECT numInstants(tfloat '{[1@2001-01-01, 2@2001-01-02), (2@2001-01-02, 3@2001-01-03)}');
      -- 3
      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 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 (number of) different timestamps

  `numTimestamps(ttype) → integer`

  `timestamps(ttype) → timestamptz[]`

      SELECT numTimestamps(tfloat '{[1@2001-01-01, 2@2001-01-03),
        [3@2001-01-03, 5@2001-01-05)}');
      -- 3
      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 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 (number of) sequences

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

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

      SELECT numSequences(tfloat '{[1@2001-01-01, 2@2001-01-03),
        [3@2001-01-03, 5@2001-01-05)}');
      -- 2
      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 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 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]"} */

## 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]} */
      SELECT setInterp(tgeometry '[Point(1 1)@2001-01-01,
        Linestring(1 1,2 2)@2001-01-02]', 'linear');
      -- ERROR:  The temporal type cannot have linear interpolation

- Return a temporal boolean stating whether each segment of a continuous temporal sequence (set) has, respectively, at least or at most a given duration

  `segmentMinDuration(temp,interval,bool strict=true) → tbool`

  `segmentMaxDuration(temp,interval,bool strict=true) → tbool`

  If `strict` is not specified, the value `true` is assumed by default, and therefore the function checks whether the segment duration is strictly less than or greater than the interval. If the argument is set to `false`, the function checks whether the segment duration is less/greater than or equal to the interval.

      SELECT segmentMinDuration(tfloat '[1@2001-01-01, 0@2001-01-03, -1@2001-01-04,
        -1@2001-01-06]', '1 day');
      -- {[t@2001-01-01, f@2001-01-03, t@2001-01-04, t@2001-01-06)}
      SELECT segmentMinDuration(tfloat '[1@2001-01-01, 0@2001-01-03, -1@2001-01-04,
        -1@2001-01-06]', '1 day', false);
      -- {[t@2001-01-01, t@2001-01-06)}
      SELECT segmentMaxDuration(tfloat '[1@2001-01-01, 0@2001-01-03, -1@2001-01-04,
        -1@2001-01-06]', '1 day');
      -- {[f@2001-01-01 00:00:00+01, f@2001-01-06 00:00:00+01)}
      SELECT segmentMaxDuration(tfloat '[1@2001-01-01, 0@2001-01-03, -1@2001-01-04,
        -1@2001-01-06]', '1 day', false);
      -- {[f@2001-01-01, t@2001-01-03, f@2001-01-04, f@2001-01-06)}

- Shift and/or scale the time span of a temporal value by one or two intervals

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

  `shiftTime(ttype,interval) → ttype`

  `scaleTime(ttype,interval) → ttype`

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

      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]} */
      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
      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(tgeometry '{[Point(1 1)@2001-01-01,
        Linestring(1 1,2 2)@2001-01-02, Point(1 1)@2001-01-03], [Point(2 2)@2001-01-04,
        Polygon((1 1,2 2,3 1,1 1))@2001-01-05]}', '1 day', '1 day'));
      /* {[POINT(1 1)@2001-01-02 00:00:00, LINESTRING(1 1,2 2)@2001-01-02 06:00:00,
          POINT(1 1)@2001-01-02 12:00:00], [POINT(2 2)@2001-01-02 18:00:00,
          POLYGON((1 1,2 2,3 1,1 1))@2001-01-03 00:00:00]} */

- 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)}
      SELECT ST_AsText((un).value), (un).time
      FROM (SELECT unnest(tgeometry '[Point(1 1)@2001-01-01,
        Linestring(1 1,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]}
      -- LINESTRING(1 1,2 2) | {[2001-01-02, 2001-01-03)}