Skip to main content

Funciones de fecha — Referencia de SQL en Marketing Cloud

Las funciones de fecha y datetime que MC SQL soporta — GETDATE, DATEADD, DATEDIFF, DATEPART, EOMONTH — más la trampa de timezone, la inestabilidad del math de meses, y la regla para filtros de fecha estables.

Referencia·Actualizado 2026-05-07·Escrito por Lira · Editado por German Medina

Las funciones de fecha en MC SQL se ven como T-SQL. Las trampas son timezone (la hora de servidor es UTC, no la tuya), math de meses (DATEADD(month, ...) devuelve resultados inconsistentes en límites de mes), y envolver columnas de fecha en funciones adentro de WHERE (mata el índice). La mayoría de los bugs de fecha en producción vienen de uno de esos tres.

Sintaxis oficial

-- Timestamp actual (UTC en MC, NO el horario local de tu tenant)
SELECT GETDATE() AS NowUtc;

-- Sumar o restar un intervalo de fecha
SELECT DATEADD(day, -90, GETDATE())     AS NoventaDiasAtras;
SELECT DATEADD(hour, 12, GETDATE())     AS DoceHorasDespues;
SELECT DATEADD(month, -3, '2026-05-31') AS RiesgosoMonthMath; -- ver gotcha abajo

-- Diferencia entre dos fechas (en unidad)
SELECT DATEDIFF(day, LastPurchase, GETDATE())   AS DiasDesdeCompra
FROM master_subscribers;

-- Extraer parte de una fecha como entero
SELECT
  YEAR(LastPurchase)              AS AnioCompra,
  MONTH(LastPurchase)             AS MesCompra,
  DAY(LastPurchase)               AS DiaCompra,
  DATEPART(weekday, LastPurchase) AS DiaSemana
FROM master_subscribers;

-- Formatear una fecha como texto vía CONVERT (códigos de estilo — ver Conversion fns)
SELECT CONVERT(VARCHAR, GETDATE(), 120) AS Iso8601;   -- 2026-05-07 14:23:11

-- Fin de mes
SELECT EOMONTH(GETDATE()) AS UltimoDiaDelMes;

El set soportado entre la mayoría de los tenants SFMC:

| Función | Qué hace | Devuelve | |---|---|---| | GETDATE() | Timestamp del servidor actual (UTC en MC) | DATETIME | | SYSDATETIME() | Igual que GETDATE() con precisión sub-segundo | DATETIME2 | | DATEADD(unit, n, date) | Suma n de unit (day, month, year, hour, etc.) | DATETIME | | DATEDIFF(unit, start, end) | Diferencia en unit entre dos fechas | INT | | DATEPART(unit, date) | Extrae parte entera (year, month, weekday, etc.) | INT | | YEAR(d) / MONTH(d) / DAY(d) | Atajo para DATEPART | INT | | EOMONTH(d) | Último día del mes de d (algunas ediciones) | DATE | | DATENAME(unit, d) | Nombre de texto de la parte (ej. 'Wednesday') | NVARCHAR | | GETUTCDATE() | Igual que GETDATE() en MC (el servidor es UTC) | DATETIME |

Unidades de DATEADD comúnmente usadas: day, month, year, hour, minute, second, week, quarter. No todas las ediciones soportan microsecond / nanosecond confiablemente — quedate con el set común.

Referencia:

Lo que sobrevive en producción

GETDATE() es UTC, no el horario local de tu tenant

Los servidores de MC corren en UTC. GETDATE() devuelve UTC, sin importar el timezone configurado en tu Business Unit. Si tu regla de negocio es "mandá entre las 9am y las 6pm hora Buenos Aires", tenés que hacer la conversión en SQL.

-- EN RIESGO — usa la hora del servidor (UTC), los sends llegan a la hora local equivocada
WHERE DATEPART(hour, GETDATE()) BETWEEN 9 AND 18;

-- DURABLE — convertí a ART (UTC-3) antes de extraer la hora
WHERE DATEPART(hour, DATEADD(hour, -3, GETDATE())) BETWEEN 9 AND 18;

-- MEJOR TODAVÍA — guardá el offset en un DE de config editable
-- sin tocar SQL (DST-aware, multi-tenant friendly)
WHERE DATEPART(hour, DATEADD(hour, (SELECT UtcOffset FROM de_config_timezone WHERE Locale = 'AR'), GETDATE())) BETWEEN 9 AND 18;

El offset hardcodeado se rompe durante las transiciones de horario de verano. El patrón de lookup las sobrevive.

DATEADD(month, ...) es inestable en límites de mes

DATEADD(month, -3, '2026-05-31') devuelve '2026-02-28' (o '2026-02-29' en año bisiesto). El resultado depende de la interpretación del motor de "el mismo día hace tres meses" cuando el día no existe en el mes destino. La misma query corrida con dos días de diferencia el día 31 puede devolver días diferentes.

-- EN RIESGO — math de meses, edge cases en límites de año y meses cortos
WHERE LastPurchase >= DATEADD(month, -3, GETDATE())

-- ESTABLE — conteo de días explícito, se comporta igual cada corrida
WHERE LastPurchase >= DATEADD(day, -90, GETDATE())   -- "últimos ~3 meses"

Si la regla de negocio es "últimos 3 meses", traducí a un conteo de días una vez en momento de diseño y documentalo. Ver gotchas — #8.

Envolver una columna de fecha en una función mata el índice

La misma regla que pega a LOWER(string_col) en WHERE pega a las funciones de fecha: cualquier función aplicada sobre la columna misma evita el uso de índice. Aplicá la función al literal en su lugar.

-- EN RIESGO — DATEADD sobre la columna, full scan
WHERE DATEADD(day, 30, LastPurchase) >= GETDATE()

-- DURABLE — transformá el literal, la columna queda pelada
WHERE LastPurchase >= DATEADD(day, -30, GETDATE())

-- EN RIESGO — YEAR() sobre la columna, full scan
WHERE YEAR(LastPurchase) = 2026

-- DURABLE — columna pelada en un lado, rango en el otro
WHERE LastPurchase >= '2026-01-01'
  AND LastPurchase <  '2027-01-01'

La primera versión de cada par devuelve las mismas filas pero paga la llamada a función en cada fila del origen. En un DE de 5M filas es la diferencia entre éxito de query y el timeout de 30 min.

Tipos de columna de fecha: DATE vs DATETIME vs DATETIME2

Una columna DATE guarda solo año-mes-día (sin hora). Una DATETIME agrega horas-minutos-segundos. Una DATETIME2 agrega precisión sub-segundo. Joinear o comparar entre tipos dispara coerción implícita.

-- EN RIESGO — comparando columna DATE a literal DATETIME, el motor
-- coerce y la comparación puede comportarse inesperadamente a medianoche
WHERE LastPurchase = '2026-05-07 00:00:00'

-- DURABLE — matcheá tipos: si la columna es DATE, compará a un literal date
WHERE LastPurchase = '2026-05-07'

-- Para columnas DATETIME, preferí comparación por rango sobre igualdad
WHERE LastPurchase >= '2026-05-07'
  AND LastPurchase <  '2026-05-08'

Cuando creás un Data Extension de destino, elegí DATE si no necesitás la hora — ahorra storage y evita la trampa de comparación a hora-cero.

Decisión rápida

Usá ventanas en cantidad de días (DATEADD(day, ...)) en lugar de cantidad de meses cuando:

  • El filtro controla elegibilidad de Send, entrada a journey, o cualquier comportamiento de producción que tiene que matchear exactamente entre corridas.

Convertí GETDATE() a hora local cuando:

  • La query expresa una regla de negocio en horas locales (ventanas de send, filtros de día hábil, reportes diarios).

Mantené las columnas de fecha peladas (sin envolver en función) en WHERE cuando:

  • El Data Extension tiene más de ~100k filas y la query está en una Activity de producción. Movele la función al lado del literal en su lugar.

Capturá GETDATE() una vez y referenciá la variable cuando:

  • La query referencia "ahora" más de una vez y los límites tienen que matchear exactamente.

Relacionado

  • Basics — subset de T-SQL soportado
  • WHERE — funciones de fecha en filtros (y la regla de columna pelada)
  • SELECT — funciones de fecha en proyección
  • INSERT INTO — matcheo de tipo de columna fecha en el destino
  • MC SQL gotchas — ver #8 (aritmética de fechas cruza límites de año)

Próximas páginas de referencia de funciones: Numeric · Conversion · Aggregate · Null Functions.

Más snippets how-to para debugging común en producción — sends de email, largo de valores, alcance de contactos, etc.