Funciones de fecha: calcular periodos y construir límites seguros
Las fechas representan instantes —puntos concretos en el tiempo— o periodos —intervalos entre dos límites—, no textos con un formato visual. Para sumar días, medir diferencias, obtener fin de mes o construir una fecha utilizamos funciones temporales y tipos apropiados.
Una de las decisiones más importantes es expresar correctamente los rangos cuando la columna también contiene hora.
Operaciones con fechas
DATEADD: desplazar una fecha
DATEADD suma una cantidad a la unidad indicada. Una cantidad negativa desplaza la fecha hacia atrás.
DATEADD(Unidad, Cantidad, Fecha)
La unidad puede ser, entre otras, DAY, MONTH o YEAR. No se escribe como texto entre comillas.
DATEDIFF: contar límites atravesados
DATEDIFF cuenta cuántos límites de la unidad indicada existen entre un inicio y un final. No mide una duración fraccionaria exacta.
DATEDIFF(Unidad, FechaInicial, FechaFinal)
DATEFROMPARTS: construir una fecha
DATEFROMPARTS recibe año, mes y día como números y devuelve un valor DATE. Si la combinación no forma una fecha válida, la función produce un error.
DATEFROMPARTS(Anio, Mes, Dia)
EOMONTH: obtener el último día del mes
EOMONTH devuelve una fecha correspondiente al último día del mes que contiene el valor recibido.
EOMONTH(Fecha)
SYSDATETIME: leer el reloj local del servidor
SYSDATETIME devuelve la fecha y hora del servidor con precisión de DATETIME2. No recibe argumentos y no representa automáticamente la zona horaria del usuario.
SYSDATETIME()
Ejemplo: sumar un periodo
SELECT
p.IdPedido,
p.FechaPedido,
DATEADD(DAY, 5, p.FechaPedido) AS FechaEstimada
FROM dbo.Pedido AS p;
El ejemplo desplaza cada fecha cinco días hacia adelante para producir una fecha estimada.
Medir una diferencia
SYSDATETIME() toma el instante actual del reloj local del servidor. No recibe argumentos; los paréntesis forman parte de la llamada a la función.
SELECT
c.IdCliente,
c.FechaRegistro,
DATEDIFF(DAY, c.FechaRegistro, SYSDATETIME()) AS DiasDesdeRegistro
FROM dbo.Cliente AS c;
DATEDIFF cuenta cuántos límites de día se atravesaron. No calcula una duración decimal exacta. Dos instantes separados por pocos segundos pueden producir 1 día si se encuentran a lados distintos de la medianoche.
Construir el inicio y final de un mes
DECLARE @Anio INT = 2026;
DECLARE @Mes INT = 3;
SELECT
DATEFROMPARTS(@Anio, @Mes, 1) AS InicioMes,
EOMONTH(DATEFROMPARTS(@Anio, @Mes, 1)) AS FinMes;
Las variables creadas mediante DECLARE se explican de forma independiente en DECLARE, SET y SELECT.
DATEFROMPARTS evita depender del idioma o formato regional de una cadena.
Filtrar un rango que contiene hora
Para consultar todos los pedidos de marzo utilizamos un límite inicial inclusivo, que sí admite el valor del límite, y uno final exclusivo, que lo deja fuera:
DECLARE @Desde DATE = '2026-03-01';
DECLARE @Hasta DATE = '2026-04-01';
SELECT
p.IdPedido,
p.FechaPedido,
p.Estado
FROM dbo.Pedido AS p
WHERE p.FechaPedido >= @Desde
AND p.FechaPedido < @Hasta
ORDER BY p.FechaPedido;
Esta forma incluye cualquier precisión de hora dentro de marzo. Evita escribir un final como 23:59:59, que puede omitir valores con mayor precisión.
Calcular el siguiente mes
Cuando solo recibimos una fecha inicial, el límite exclusivo puede derivarse:
DECLARE @InicioMes DATE = '2026-03-01';
DECLARE @InicioSiguienteMes DATE = DATEADD(MONTH, 1, @InicioMes);
Qué conviene comprobar
Debemos distinguir DATE, DATETIME, DATETIME2 y valores con zona u offset. Un offset es la diferencia numérica respecto de UTC que acompaña a un instante. SYSDATETIME() utiliza el reloj local del servidor; no representa automáticamente la zona del usuario.
También evitamos convertir la columna a texto dentro del filtro. Comparar un rango temporal conserva el significado del dato y normalmente ofrece mejores posibilidades de utilizar un índice, una estructura que organiza valores para facilitar el acceso a filas.