# Tipos temporales

## Introduction

MobilityDB proporciona seis tipos temporales nativos, a saber, `tbool`, `tint`, `tfloat`, `ttext`, `tgeompoint` y `tgeogpoint`, que se basan, respectivamente, en los tipos de base `bool`, `integer`, `float`, `text`, `geometry` y `geography` (los dos últimos tipos restringidos a puntos 2D o 3D con dimensión Z).

La interpolación de un valor temporal establece cómo evoluciona el valor entre instantes sucesivos. La interpolación es discreta cuando se desconoce el valor entre dos instantes sucesivos. Pueden representar, por ejemplo, entradas/salidas cuando se utiliza un lector de tarjetas RFID para entrar o salir de un edificio. La interpolación es escalonada cuando el valor permanece constante entre dos instantes sucesivos. Por ejemplo, la marcha que utiliza un automóvil en movimiento puede representarse con un número entero temporal, lo que indica que su valor es constante entre dos instantes de tiempo. Por otro lado, la interpolación es lineal cuando el valor evoluciona linealmente entre dos instantes sucesivos. Por ejemplo, la velocidad de un automóvil puede representarse con un flotante temporal, lo que indica que los valores se conocen en los instantes de tiempo pero evolucionan continuamente entre ellos. De manera similar, la ubicación de un vehículo se puede representar mediante un punto temporal en el que la ubicación entre dos lecturas GPS consecutivas se obtiene mediante interpolación lineal. Los tipos temporales basados en tipos base discretos, es decir `tbool`, `tint` o `ttext` evolucionan necesariamente de manera escalonada. Por otro lado, los tipos temporales basados en tipos base continuos, es decir `tfloat`, `tgeompoint` o `tgeogpoint` pueden evolucionar de manera lineal o escalonada.

El subtipo de un valor temporal establece la extensión temporal en la que se registra la evolución de los valores. Los valores temporales vienen en tres subtipos, explicados a continuación.

Un valor temporal de subtipo instante (brevemente, un valor de instante) representa el valor en un instante de tiempo, por ejemplo

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

Un valor temporal de subtipo secuencia (brevemente, un valor de secuencia) representa la evolución del valor durante una secuencia de instantes de tiempo, donde los valores entre estos instantes se interpolan usando una función discreta, escalonada, o lineal (ver arriba). Un ejemplo es el siguiente:

    -- Interpolación discreta
    SELECT tfloat '{17@2018-01-01 08:00:00, 17.5@2018-01-01 08:05:00, 18@2018-01-01 08:10:00}';
    -- Interpolación escalonada
    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]';
    -- Interpolación lineal
    SELECT tfloat '(10@2018-01-01 08:00:00, 20@2018-01-01 08:05:00, 15@2018-01-01 08:10:00]';

Como puede verse, un valor de secuencia tiene un límite superior e inferior que pueden ser inclusivos (representados por ‘`[`’ y ‘`]`’) o exclusivos (representados por ‘`(`' y ‘`)`'). Por definición, ambos límites deben ser inclusivos cuando la interpolación es discreta o cuando la secuencia tiene un solo instante (que se llama secuencia instantánea), como el ejemplo suiguiente.

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

Los valores de secuencia deben ser uniformes, es decir, deben construirse a partir de valores de instante del mismo tipo de base. Los valores de secuencia con interpolación escalonada o lineal se denominan secuencias continuas.

El valor de una secuencia temporal se interpreta asumiendo que el período de tiempo definido por cada par de valores consecutivos `v1@t1` y `v2@t2` es inferior inclusivo y superior exclusivo, a menos que sean el primer o el último instantes de la secuencia y, en ese caso, se aplican los límites de toda la secuencia. Además, el valor que toma la secuencia temporal entre dos instantes consecutivos depende de si la interpolación es escalonada o lineal. Por ejemplo, la secuencia temporal anterior representa que el valor es `10` durante`(2018-01-01 08:00:00, 2018-01-01 08:05:00)`, `20` durante `[2018-01-01 08:05:00, 2018-01-01 08:10:00)` y `15` en el instante final `2018-01-01 08:10:00`. Por otro lado, la siguiente secuencia temporal

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

representa que el valor evoluciona linealmente de `10` a `20` durante `(2018-01-01 08:00:00, 2018-01-01 08:05:00)` y evoluciona de `20` a `15` durante `[2018-01-01 08:05:00, 2018-01-01 08:10:00]`.

Finalmente, un valor temporal de subtipo conjunto de secuencias (brevemente, un valor de conjunto de secuencias) representa la evolución del valor en un conjunto de secuencias, donde se desconocen los valores entre estas secuencias. Un ejemplo es el siguiente:

    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]}';

Como se muestra en los ejemplos anteriores, los valores de conjunto de secuencias solo pueden ser de interpolación escalonada o lineal. Además, todas las secuencias que componen un valor de conjunto de secuencias deben ser del mismo tipo de base y de la misma interpolación.

Los valores de secuencia continuos se convierten en forma normal de modo que los valores equivalentes tengan representaciones idénticas. Para ello, los valores de instante consecutivos se fusionan cuando es posible. Para la interpolación escalonada, tres valores instantáneos consecutivos se pueden fusionar en dos si tienen el mismo valor. Para la interpolación lineal, tres valores instantáneos consecutivos se pueden fusionar en dos si las funciones lineales que definen la evolución de los valores son las mismas. Ejemplos de transformación en forma normal son los siguientes.

    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]

De manera similar, los valores del conjunto de secuencias temporales se convierten en forma normal. Para ello, los valores de secuencia consecutivos se fusionan cuando es posible. Ejemplos de transformación en forma normal son los siguientes.

    SELECT tint '{[1@2001-01-01, 1@2001-01-03), [2@2001-01-03, 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 tfloat '{[1@2001-01-01, 2@2001-01-03), [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 tfloat '{[1@2001-01-01, 3@2001-01-05), [3@2001-01-05]}';
    -- '{[1@2001-01-01 00:00:00+00, 3@2001-01-05 00:00:00+00]}'
    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]}

Los tipos temporales soportan modificadores de typo (o `typmod` en terminología de PostgreSQL), que especifican información adicional para la definición de una columna. Por ejemplo, en la siguiente definición de tabla:

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

el modificador de tipo para el tipo `varchar` es el valor 25, que indica la longitud máxima de los valores de la columna, mientras que el modificador de tipo para el tipo `tint` es la cadena de caracteres `Sequence`, que restringe el subtipo de los valores de la columna para que sean secuencias. En el caso de tipos alfanuméricos temporales (es decir, `tbool`, `tint`, `tfloat` y `ttext`), los valores posibles para el modificador de tipo son `Instant`, `Sequence` y `SequenceSet`. Si no se especifica ningún modificador de tipo para una columna, se permiten valores de cualquier subtipo.

Por otro lado, en el caso de tipos de puntos temporales (es decir, `tgeompoint` o `tgeogpoint`) el modificador de tipo se puede utilizar para especificar el subtipo, la dimensionalidad y/o el identificador de referencia espacial (SRID). Por ejemplo, en la siguiente definición de tabla:

    CREATE TABLE Flight(FlightNo integer, Route tgeogpoint(Sequence, PointZ, 4326));

el modificador de typo para el tipo `tgeogpoint` se compone de tres valores, el primero indica el subtipo como arriba, el segundo el tipo espacial de las geografías que componen el punto temporal y el último el SRID de las geografías que componen. Para los puntos temporales, los valores posibles para el primer argumento del modificador de tipo son los anteriores, los del segundo argumento son `Point` o `PointZ` y los del tercer argumento son SRID válidos. Los tres argumentos son opcionales y si alguno de ellos no se especifica para una columna, se permiten valores de cualquier subtipo, dimensionalidad y/o SRID.

Cada tipo temporal está asociado a otro tipo, conocido como su cuadro delimitador, que representan su extensión en la dimensión de valor y/o tiempo. El cuadro delimitador de los distintos tipos temporales es el siguiente:

- El tipo `tstzspan` para los tipos `tbool` y `ttext`, donde solo se considera la extensión temporal.

- El tipo `tbox` (temporal box) par los tipos `tint` y `tfloat`, donde la extensión del valor y de tiempo se define, respectivamente, por un rango numérico y un rango de tiempo.

- El tipo `stbox` (spatiotemporal box) para los tipos `tgeompoint` y `tgeogpoint`, donde la extensión espacial se define en las dimensiones X, Y y Z y la extensión de timpo se define en un rango de tiempo.

Un amplio conjunto de funciones y operadores son disponibles para realizar varias operaciones en los tipos temporales. Estos se explican a continuación y en los próximos capítulos. Algunas de estas operaciones, en particular las relacionadas con índices, manipulan cuadros delimitadores por razones de eficiencia.

## Ejemplos de tipos temporales

A continuación se dan ejemplos de uso de tipos alfanuméricos temporales.

    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}');

    -- Valor en una marca de tiempo
    SELECT RoomNo, valueAtTimestamp(Temp, '2001-01-01 08:10:00')
    FROM temperature;
    -- 1001 | 20
    -- 2001 | 22.5

    -- Restricción a un valor
    SELECT DeptNo, atValues(NoEmps, 10)
    FROM Department;
    -- 10 | [10@2001-01-01, 10@2001-04-01)
    -- 20 |

    -- Restricción a un período
    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]

    -- Comparación temporal
    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)

    -- Agregación temporal
    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)} */

A continuación se dan ejemplos de uso de tipos de puntos temporales.

    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)}');

    -- Valor en una marca de tiempo
    SELECT CarId, ST_AsText(valueAtTimestamp(Trip, timestamptz '2001-01-01 08:10:00'))
    FROM Trips;
    -- 10 | POINT(2 0)
    -- 20 | POINT(1 1)

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

    -- Restricción a un período
    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]}

    -- Distancia temporal
    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)} */

## Validez de los tipos temporales

Los valores de los tipos temporales deben satisfacer varias restricciones para que estén bien definidos. Estas restricciones se dan a continuación.

- Las restricciones en el tipo base y el tipo `timestamptz` deben satisfacerse.

- Un valor de secuencia debe estar compuesto por al menos un valor de instante.

- Un valor de secuencia instantánea o con interpolación discreta debe tener límites inferior y superior inclusivos.

- En un valor de secuencia, las marcas de tiempo de los instantes que la componen deben ser diferentes y estar ordenadas.

- En un valor de secuencia con interpolación escalonada, los dos últimos valores deben ser iguales si el límite superior es exclusivo.

- Un valor de conjunto de secuencias debe estar compuesto por al menos un valor de secuencia.

- En un valor de conjunto de secuencias, los valores de las secuencias componentes no deben superponerse y deben estar ordenados.

Se genera un error cuando no se satisface una de estas restricciones. Ejemplos de valores temporales incorrectos son los siguientes.

    -- Valor del tipo de base incorrecto
    SELECT tbool '1.5@2001-01-01 08:00:00';
    -- Valor del tipo base no es un punto
    SELECT tgeompoint 'Linestring(0 0,1 1)@2001-01-01 08:05:00';
    -- Marca de tiempo incorrecta
    SELECT tint '2@2001-02-31 08:00:00';
    -- Secuencia vacía
    SELECT tint '';
    -- Límites incorrectos para la secuencia instantánea
    SELECT tint '[1@2001-01-01 09:00:00)';
    -- Marcas de tiempo duplicadas
    SELECT tint '[1@2001-01-01 08:00:00, 2@2001-01-01 08:00:00]';
    -- Marcas de tiempo desordenadas
    SELECT tint '[1@2001-01-01 08:10:00, 2@2001-01-01 08:00:00]';
    -- Valor final incorrecto para interpolación escalonada
    SELECT tint '[1@2001-01-01 08:00:00, 2@2001-01-01 08:10:00)';
    -- Conjunto de secuencias vacío
    SELECT tint '{[]}';
    -- Marcas de tiempo duplicadas
    SELECT tint '{1@2001-01-01 08:00:00, 2@2001-01-01 08:00:00}';
    -- Períodos superpuestos
    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)}';