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.

Relacionado con