Funciones de fecha — referencia de Marketing Cloud AMPscript
La superficie de fecha de AMPscript — Now / DateAdd / DateDiff / DatePart / FormatDate / DateParse. La trampa de timezone (el reloj de sistema de MC es CST independientemente de donde esté el tenant), la inestabilidad del math de meses, y los patrones que sobreviven a escala.
Las funciones de fecha de AMPscript son una capa funcional fina sobre el modelo de fecha estilo .NET que Marketing Cloud corre en el server. Más chica que la superficie de SQL (sin operadores, sin BETWEEN, sin atajos DATEPART para nombre de día), más grande que la de SSJS (que mayormente hereda el frágil Date de JavaScript). Las siete funciones de esta página cubren ~95% de las necesidades de personalización: Now, DateAdd, DateDiff, DatePart, FormatDate, DateParse, más el par de timezone SystemDateToLocalDate / LocalDateToSystemDate.
Las dos trampas que se disparan más seguido: el reloj de sistema de MC es CST (Central Standard Time, US) independientemente de donde tu tenant esté provisionado, y DateAdd con unidades de mes es inestable alrededor de los bordes de mes. Las dos están cubiertas abajo.
Sintaxis oficial
%%[
/* Fecha/hora actual — server time, CST */
SET @now = Now() /* → 2026-05-13 14:32:08 */
SET @sysNow = SystemDate() /* alias de Now() */
/* DateAdd — sumar o restar unidades */
SET @yesterday = DateAdd(Now(), -1, "Day")
SET @nextWeek = DateAdd(Now(), 7, "Day")
SET @nextHour = DateAdd(Now(), 1, "Hour")
SET @inAYear = DateAdd(Now(), 1, "Year")
SET @monthOut = DateAdd(Now(), 1, "Month") /* ver trampa del math de meses abajo */
/* DateDiff — diferencia entre dos fechas, en la unidad elegida */
SET @daysSince = DateDiff(@orderDate, Now(), "Day")
SET @hoursSince = DateDiff(@lastLogin, Now(), "Hour")
/* DateDiff es later - earlier; negativo si invertís */
/* DatePart — extraer un componente */
SET @year = DatePart(Now(), "year") /* numérico */
SET @month = DatePart(Now(), "month") /* numérico */
SET @day = DatePart(Now(), "day") /* numérico */
SET @hour = DatePart(Now(), "hour") /* numérico, 24h */
SET @minute = DatePart(Now(), "minute") /* numérico */
SET @wday = DatePart(Now(), "weekday") /* STRING: "Wednesday" */
SET @mname = DatePart(Now(), "monthname") /* STRING: "May" */
/* FormatDate — fecha a string formateado */
SET @yyyymmdd = FormatDate(Now(), "yyyy-MM-dd")
SET @longDate = FormatDate(Now(), "MMMM d, yyyy", "en-US")
/* → "May 13, 2026" */
/* DateParse — string a fecha (devuelve un valor de fecha, no un string) */
SET @parsed = DateParse("2026-05-13")
SET @parsedTz = DateParse("2026-05-13 09:00:00", 1)
/* El 2do arg opcional (1) le dice a AMPscript que el input es local-time;
si no, se interpreta como CST del server. */
/* Conversión de timezone — útil para personalizar en el TZ del destinatario
cuando tenés su offset guardado. */
SET @localized = SystemDateToLocalDate(@cstDate)
SET @backToCst = LocalDateToSystemDate(@localDate)
]%%
<p>Hoy es %%=v(@longDate)=%%.</p>El set soportado:
| Función | Qué hace | Notas |
|---|---|---|
| Now() | Fecha/hora actual del server | CST, siempre (el reloj de sistema de Marketing Cloud) |
| SystemDate() | Alias de Now() | Mismo retorno; nombre explícito cuando importa el contexto |
| LocalDate() | Hora local del destinatario, si MC tiene info de TZ | Fallback a CST cuando no hay TZ disponible |
| DateAdd(date, n, unit) | Sumar n unidades a date | Unidades: Day, Hour, Minute, Second, Month, Year |
| DateDiff(d1, d2, unit) | d2 - d1 en unit (redondea hacia abajo) | Mismos nombres de unidad que DateAdd |
| DatePart(date, part) | Extraer un componente | Algunos parts devuelven numérico, otros strings (ver abajo) |
| FormatDate(date, fmt [, locale]) | Formatear como string | Ver funciones de string para la trampa de locale |
| DateParse(str [, isLocal]) | Parsear string → fecha | Parsing flexible; pasá 1 para marcar el string como local-time |
| SystemDateToLocalDate(d) | Convertir CST → local del subscriber | Necesita TZ en el subscriber |
| LocalDateToSystemDate(d) | Convertir local → CST | El reverso |
Referencia:
- AMPscript Guide — referencia de funciones (sección de fecha) ↗
- Salesforce Developer — funciones AMPscript ↗
Lo que sobrevive en producción
El reloj del server de Marketing Cloud es CST, independientemente de la región del tenant
Now() y SystemDate() los dos devuelven Central Standard Time (US), no el timezone de la geografía del tenant. Un tenant provisionado en EU devuelve 2026-05-13 14:32:08 como un timestamp CST — el mismo momento en hora local de EU es más tarde.
%%[
/* Devuelve CST, incluso si tu negocio está en Buenos Aires o París */
SET @now = Now()
/* Si necesitás hora local del destinatario, convertí DESPUÉS del read */
SET @local = SystemDateToLocalDate(@now)
/* Si el subscriber no tiene TZ en el perfil, SystemDateToLocalDate
hace fallback devolviendo el valor CST. Confirmá TZ en el DE
sendable antes de apoyarte en personalización por hora local. */
]%%La trampa se manifiesta más seguido cuando AMPscript corre un check de "¿es hoy el cumpleaños del destinatario?" usando Now() directamente — para un destinatario en Asia, la fecha CST no rotó todavía cuando su fecha local ya lo hizo. O guardás los valores de comparación en CST también, o convertís explícitamente con SystemDateToLocalDate antes de comparar.
DateAdd con Month y Year es inestable alrededor de los bordes
DateAdd(Now(), -3, "Month") no es "exactamente 3 meses calendario atrás, mismo día del mes" — es aproximado. En el 31 de un mes de 31 días, tres meses atrás aterriza en el 28, 30, o 31 según el largo del mes destino, y la regla no siempre es intuitiva. Lo mismo aplica a fin de año con DateAdd(d, 1, "Year") sobre una fecha 29 de febrero de año bisiesto.
%%[
/* ESTABLE — la aritmética de días es exacta */
SET @ninetyDaysAgo = DateAdd(Now(), -90, "Day")
/* INESTABLE — la aritmética de mes calendario se mueve alrededor de los fin-de-mes */
SET @threeMonthsAgo = DateAdd(Now(), -3, "Month")
]%%Misma trampa que el gotcha de las funciones de fecha de SQL. Traducí "últimos 3 meses" a "últimos 90 días" en momento de diseño, y quedate en aritmética de días para cualquier cálculo que fluya a una comparación o un filtro WHERE downstream.
DateDiff redondea hacia abajo, no al unidad más cercana
DateDiff(d1, d2, "Day") devuelve el número entero de unidades completas entre dos fechas — no redondea al más cercano. Un gap de 23-horas-59-minutos devuelve 0 días, no 1.
%%[
/* @lastOrder = 2026-05-13 09:00:00
@now = 2026-05-14 08:59:00 (un minuto corto de 24h) */
SET @daysSince = DateDiff(@lastOrder, @now, "Day")
/* → 0 — NO 1 */
/* Usá Hour para precisión sub-día */
SET @hoursSince = DateDiff(@lastOrder, @now, "Hour")
/* → 23 */
]%%La lógica condicional IF DateDiff(@lastLogin, Now(), "Day") > 30 THEN ... excluye a cualquier destinatario cuya marca de 30 días caiga dentro de hoy — están en 29 días, 23 horas, 50 minutos y la función devuelve 29. Padeá la comparación con una unidad más chica (> 30 días → > 720 horas) cuando el borde importa.
DatePart devuelve números para algunos parts, strings para otros
%%[
/* Parts numéricos */
SET @y = DatePart(Now(), "year") /* 2026 */
SET @m = DatePart(Now(), "month") /* 5 — NO "May", NO "05" */
SET @d = DatePart(Now(), "day") /* 13 */
SET @h = DatePart(Now(), "hour") /* 14 */
/* Parts string — devuelven nombres locale-aware */
SET @wday = DatePart(Now(), "weekday") /* "Wednesday" */
SET @mname = DatePart(Now(), "monthname") /* "May" */
]%%La falla del hand-off: un dev escribe IF DatePart(@d, "month") == "May" y obtiene false-en-todos-lados porque la función devolvió el entero 5. A la inversa, comparar el número del weekday esperando un nombre devuelve la forma equivocada.
La regla: usá parts numéricos (year, month, day, hour, minute) para aritmética y comparaciones, y parts string (weekday, monthname) solo para display en personalización. No compares contra parts string a menos que hayas dado cuenta explícitamente del locale y no los estés mostrando.
DateParse es flexible, pero la flag de timezone importa
DateParse acepta muchos formatos — "2026-05-13", "05/13/2026", "May 13, 2026 9:00 AM". La flexibilidad es conveniente hasta que dos sistemas discrepan sobre cuál significa qué.
%%[
/* Interpretación server-time (default) */
SET @d = DateParse("2026-05-13 09:00:00")
/* AMPscript trata esto como 09:00 CST */
/* Interpretación local-time — el 2do arg = 1 marca el input como local */
SET @dLocal = DateParse("2026-05-13 09:00:00", 1)
/* AMPscript trata esto como 09:00 en el TZ local del subscriber si
está presente en el perfil, si no fallback a CST */
]%%Cuando el string fuente vino de un sistema que emite un TZ específico (un objeto de Salesforce que registra LastModified en UTC, por ejemplo), parseá con la flag correcta y convertí explícitamente. No te apoyes en que AMPscript adivine.
FormatDate devuelve un string — encadenar funciones de string downstream se lee raro
FormatDate(Now(), "yyyy-MM-dd") devuelve el string "2026-05-13", no un valor de fecha. Esto traba código que espera que el retorno alimente de vuelta a DateAdd o DateDiff — esos necesitan valores de fecha, no strings.
%%[
/* MAL — el output de FormatDate no puede alimentar DateAdd directamente */
SET @str = FormatDate(Now(), "yyyy-MM-dd")
SET @plus = DateAdd(@str, 1, "Day") /* PUEDE funcionar vía DateParse implícito,
pero el comportamiento no está garantizado */
/* BIEN — mantené el math de fechas en valores de fecha; formateá solo para output */
SET @plus = DateAdd(Now(), 1, "Day")
SET @plusStr = FormatDate(@plus, "yyyy-MM-dd")
]%%La convención de Cleon: hacé toda la aritmética de fechas sobre valores de fecha, y después formateá una vez al final a un string para interpolación. No pases strings entre funciones de fecha incluso cuando la conversión implícita justo funcione.
El preview de personalización puede usar un "now" distinto
El preview de Email Studio evalúa Now() en el momento que se renderea el preview — no en el momento que el send de producción va a correr. Una personalización countdown de "te quedan N horas" puede mostrar "23 horas restantes" en preview a las 11pm y "1 hora restante" en el send-time real de las 9pm del día siguiente.
La defensa: cuando el email contiene personalización time-sensitive, hacé un test send a una hora cercana a la hora del send de producción, no solo un preview. Ver gotchas — #9.
Decisión rápida
Usá Now() cuando:
- Necesitás un timestamp ancla único para el render actual. Capturá una vez, reusá.
Usá DateAdd con unidades de día (no mes/año) cuando:
- La aritmética cruza cualquier borde que importe. "Últimos 90 días" le gana a "últimos 3 meses" cada vez.
Usá DateDiff con la unidad más chica significativa cuando:
- El borde importa. "Más de 30 días" → usá horas (720) si te importa el borde.
Usá DatePart con parts numéricos (year, month, day, hour) cuando:
- Comparás o ramificás. Los parts string (
weekday,monthname) son solo para display.
Usá FormatDate cuando:
- El output se renderea en el email. Siempre confirmá locale por separado.
Usá DateParse con flag de locale/TZ explícito cuando:
- Parseás strings de otro sistema. No confíes en el parsing default entre fuentes de data.
Hacé el trabajo en SQL en su lugar cuando:
- Calculás "días desde X" para una audiencia grande. Pre-computá como una columna numérica en un DE
de_email_*upstream; AMPscript lee la columna literalmente. - Comparás fechas entre timezones. SQL tiene funciones explícitas de conversión de TZ y aritmética más clara.
- El mismo math de fechas corre para cada destinatario en un send de 50k. Una corrida SQL le gana a 50.000 corridas AMPscript.
Relacionado
- Basics — superficie del lenguaje soportada
- Funciones de string —
FormatDatedevuelve un string; las reglas de locale viven ahí - Gotchas de MC AMPscript — ver #9 (preview ≠ send para personalización time-sensitive)
- MC SSJS — funciones de fecha — la superficie hermana; SSJS hereda el modelo
Datede JavaScript y agregaPlatform.Function.SystemDateToLocalDateetc. - MC SQL — funciones de fecha — el upstream donde la mayoría del math de fechas debería pasar para audiencias grandes
Más páginas de referencia AMPscript en camino: Math · Validación · Data Extension · Subscriber/Profile · Cloud-write · Encoding/Hashing · Style Guide.