Fechas y tiempo
Fechas y tiempos
La administración y manejo de valores temporales es la parte de los motores de base de datos menos estandarizada y con más diferencias entre uno y otro. Aparte, y junto con la codificación de caracteres y las características regionales (por ejemplo, formato de las fechas) el motor ofrecee un conjunto de parámetros globales del sistema que el administrador del mismo debe comprender y tener presente, dependiendo del contexto en el que se vayan a ver los resultados de una consulta. Si fuera a formar parte de un conjunto de páginas web dinámicas, no solo el servidor de base de datos debe estar correctamente configurado sino que debe tener en cuenta el servidor http, el del lenguaje huesped (php, por ejemplo) e incluso los clientes (navegadores, ordenadores, etc.).
Puestas así las cosas, aquí se va a tratar la superficie de todo lo que se puede hacer con fechas y tiempos, y siempre desde el punto de vista estrictamente de la consulta SQL.
MariaDB/MySQL ofrece varios tipos de datos relacionados con el tiempo:
DATETIME '0000-00-00 00:00:00'
DATE '0000-00-00'
TIMESTAMP 00000000000000
TIME '00:00:00'
YEAR 0000
Lo que se muestra en la lista anterior da una idea de qué datos maneja cada tipo. En realidad, lo anterior es la relación de "valores cero" que pueden almacenar y que tienen carácter de valor por defecto o valor de prueba. Dejando de lado el tipo TIMESTAMP que tiene unas propiedades y aplicaciones propias, todos los tipos están relacionados y difieren en cuanto a las limitaciones de almacenamiento y, más importante, de conversión automática de tipos.
De cadenas de caracteres, números y fechas y tiempos
Las fechas, salvo por el uso de funciones que se menciona más adelante, se tratan igual que las cadenas de caracteres. De hecho, las constantes se entrecomillan igualmente. Por tanto, se pueden utilizar en comparaciones de igualdad, desigualdad, mayor que, etc.
Profesores que han ingresado antes de 1990.
select *
from profesores
where ingreso < '1990-01-01';
Nótese que se está comparando un tipo date con una cadena de caracteres. Lo que ocurre es que MySQL analiza la cadena y determina si tiene un formato adecuado para el tipo de datos y la procesa si así es. De hecho, aunque la salida genérica de una fecha siempre es aaaa-mm-dd, la cadena de caracteres que usamos para la comparación asume cierta libertad de formato:
ingreso < '1990@01@01'
ingreso < '1990/01/01'
ingreso < '1990.01.01'
ingreso < '1990:01:01'
En todos los casos el resultado es idéntico al anterior.
Lo que ya no funciona es
select *
from profesores
where ingreso < '01-01-1990'
0 rows selected
Y, además, no se genera ningún mensaje de error, simplemente, no muestra fila alguna en el resultado.
0 filas encontradas
Tampoco se comporta como nosotros esperaríamos
select *
from profesores
where ingreso < 1990-01-01;
0 filas encontradas
Pero sí
select *
from profesores
where ingreso < 19900101;
Otro aspecto en el que se da cierta libertad es en la forma del año:
select *
from profesores
where ingreso < '90-01-01';
Ahora bien, hay que tener en cuenta que MySQL hace una interpretación de esa parte de la fecha de tal forma que años en el rango 00-69 los convierte en 2000-2069, y los 70-99 en 1970-1999. Si manejamos años anteriores o posteriores debemos usar los 4 caracteres.
Más información sobre funciones específicas para manejar fechas en "funciones de fecha y tiempo".
Funciones de fecha y hora
El conjunto de funciones que ofrece cada producto —MySQL, SQL Server, Oracle Database, etc.— suele ser particular de cada uno aunque, al final, ofrezcan más o menos la misma operativa. Esto es más evidente en las funciones de fecha y hora, muy dependientes de cómo se gestiona el almacenamiento de este tipo de datos en cada marca de servidor de base de datos. También es cierto que, aparte de cambios mínimos en los nombres y los parámetros de las funciones —y algo menos en los formatos—, cada vez se está consensuando más un núcleo de funciones estándar.
En el manual de referencia de MariaDB puede consultarse la lista completa de funciones para el manejo del tiempo. Aquí solo expondremos algunas:
now(), curdate(), curtime()
date_format(), str_to_date()
day(), dayofweek(), dayname(), month(), year(), hour(), minute(), second()
Ahora
La función now() devuelve la fecha y hora del servidor en formato datetime. Curdate() y curtime() hacen lo mismo pero con la fecha y la hora respectivamente.
select now(), curdate(), curtime();
Formato
Se trata de mostrar o transformar el formato de la fecha. Las funciones principales de formato podemos decir que son
date_format()
str_to_date()
Recordemos que el tipo fecha, o tiempo, no es una cadena de texto, tiene un almacenamiento especial, aunque lo escribamos entre comillas. Una es la inversa de la otra: dateformat() transforma la fecha a texto, y str_to_date() una cadena de caracteres a tipo fecha. Las dos trabajan con 2 parámetros, una expresión y una cadena de formato. La cadena de formato indica a la función qué aspecto tiene o queremos que tenga —depende de si es una u otra función— el dato que le suministramos en el primer parámetro:
Profesores, con la fecha de ingreso en formato "dd/mm/aaaa".
select dni, nombre, date_format(ingreso, '%d/%m/%Y') ingreso
from profesores;
Date_format() transforma el formato nativo de MariaDB/MySQL al que nosotros le pidamos. En este caso queremos que nos muestre la fecha de ingreso en el formato "día/mes/año con cuatro cifras". Los códigos que se pueden utilizar en estas cadenas de formato —como %d, %m o %Y— se pueden consultar igualmente en el manual de MariaDB.
En este caso hacemos todo lo contrario, y suministramos una cadena de formato para que MariaDB/MySQL pueda interpretar correctamente el valor de texto como una fecha válida:
Profesores que han ingresado antes de 1/1/1990.
select *
from profesores
where ingreso < str_to_date('1/1/90','%d/%m/%y');
Por la razón que sea —piénsese en un programa de ordenador que esté accediendo al servidor— la fecha que debemos consultar está en un formato especial, "día/mes/año con 2 cifras". El primer parámetro es la fecha, y el segundo el formato en el que MariaDB/MySQL debe leer la anterior. De esta forma, MariaDB/MySQL sabe cómo transformarla a su formato nativo, '1990-01-01', y comparar con las almacenadas en la tabla.
Así, la cadena de formato para la primera consulta representa "cómo queremos la salida" y la de la segunda "cómo está escrita la fecha que quiero comparar".
Extracción
Las otras funciones a las que vamos a prestar atención son las que extraen parte de la expresión temporal. En todos estos ejemplos vamos a trabajar con el día, el més o el año de las fechas, y con varios tipos de información posible.
Día del mes, mes, y año de la fecha de ingreso de las profesoras llamadas 'Eva Gómez'.
select day(ingreso) día, month(ingreso) mes, year(ingreso) año
from profesores
where nombre='EVA GOMEZ';
Día de la semana, mes, y nombre del mes de la fecha de ingreso de las profesoras llamadas 'Eva Gómez'.
select dayname(ingreso) d, dayofweek(ingreso) nd, monthname(ingreso) m
from profesores
where nombre='EVA GOMEZ';
Fecha y hora del sistema, con formato "añomesdía -- hora:minutos:segundos"
select date_format(now(),'%Y%m%d -- %H:%i:%s') ahora;
Evidentemente, se pueden hacer muchas más cosas con fechas y tiempos —diferencia en días entre dos fechas, por ejemplo—. Tan solo hay que acudir al manual de MariaDB o a los muchos ejemplos que se pueden encontrar en una simple búsqueda.